2008-01-21 21:24:39 +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-01-21 21:24:39 +00:00
|
|
|
*
|
2015-07-07 17:49:03 +00:00
|
|
|
* Copyright (C) 2007-2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
2020-08-18 14:17:16 +00:00
|
|
|
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.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:
|
2008-09-17 13:32:43 +00:00
|
|
|
http://tech.groups.yahoo.com/group/kicad-users/files/ then file "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.
|
|
|
|
*/
|
|
|
|
|
2018-01-29 20:58:58 +00:00
|
|
|
#include <pcb_edit_frame.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <confirm.h> // DisplayError()
|
|
|
|
#include <gestfich.h> // EDA_FileSelector()
|
|
|
|
#include <trigo.h> // RotatePoint()
|
2013-05-02 18:06:58 +00:00
|
|
|
#include <macros.h>
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <math/util.h> // for KiROUND
|
2011-09-23 13:57:12 +00:00
|
|
|
|
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
|
|
|
|
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>
|
2012-04-27 14:15:11 +00:00
|
|
|
#include <base_units.h>
|
2017-11-12 00:31:38 +00:00
|
|
|
#include <wildcards_and_files_ext.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <collectors.h>
|
2015-07-27 19:45:57 +00:00
|
|
|
#include <geometry/shape_poly_set.h>
|
2018-02-02 17:49:02 +00:00
|
|
|
#include <geometry/convex_hull.h>
|
2018-02-03 17:50:55 +00:00
|
|
|
#include <convert_basic_shapes_to_polygon.h>
|
2018-03-08 12:48:29 +00:00
|
|
|
#include <geometry/geometry_utils.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <pcbnew_settings.h>
|
2015-07-27 19:45:57 +00:00
|
|
|
|
2018-01-29 17:09:18 +00:00
|
|
|
#include "specctra.h"
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2008-01-21 22:16:45 +00:00
|
|
|
using namespace DSN;
|
|
|
|
|
2018-02-02 17:49:02 +00:00
|
|
|
// comment the line #define EXPORT_CUSTOM_PADS_CONVEX_HULL to export CUSTOM pads exact shapes.
|
|
|
|
// Keep in mind shapes can be non convex polygons with holes (linked to outline)
|
|
|
|
// that can create issues.
|
|
|
|
// Especially Freerouter does not handle them very well:
|
|
|
|
// - too complex shapes are not accepted, especially shapes with holes (dsn files are not loaded).
|
|
|
|
// - and Freerouter actually uses something like a convex hull of the shape (that works not very well).
|
|
|
|
// I am guessing non convex polygons with holes linked could create issues with any Router.
|
|
|
|
#define EXPORT_CUSTOM_PADS_CONVEX_HULL
|
2008-01-21 21:24:39 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
// Add .1 mil to the requested clearances as a safety margin.
|
|
|
|
// There has been disagreement about interpretation of clearance in the past
|
2011-09-30 18:15:37 +00:00
|
|
|
// between KiCad and Freerouter, so keep this safetyMargin until the
|
2009-09-10 15:22:26 +00:00
|
|
|
// disagreement is resolved and stable. Freerouter seems to be moving
|
|
|
|
// (protected) traces upon loading the DSN file, and even though it seems to sometimes
|
|
|
|
// add its own 0.1 to the clearances, I believe this is happening after
|
|
|
|
// the load process (and moving traces) so I am of the opinion this is
|
|
|
|
// still needed.
|
2013-04-30 15:25:41 +00:00
|
|
|
static const double safetyMargin = 0.1;
|
|
|
|
|
|
|
|
|
2014-03-27 17:45:05 +00:00
|
|
|
bool PCB_EDIT_FRAME::ExportSpecctraFile( const wxString& aFullFilename )
|
|
|
|
{
|
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();
|
2012-04-26 20:21:31 +00:00
|
|
|
bool wasModified = screen->IsModify();
|
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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
LOCALE_IO toggle; // Switch the locale to standard C
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +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.
|
2009-01-05 05:21:35 +00:00
|
|
|
db.FlipMODULEs( GetBoard() );
|
2008-02-29 06:49:34 +00:00
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
try
|
|
|
|
{
|
2009-09-10 15:22:26 +00:00
|
|
|
GetBoard()->SynchronizeNetsAndNetClasses();
|
2009-01-05 05:21:35 +00:00
|
|
|
db.FromBOARD( GetBoard() );
|
2019-08-03 03:03:03 +00:00
|
|
|
db.ExportPCB( aFullFilename, 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
|
|
|
}
|
2014-04-09 13:33:04 +00:00
|
|
|
catch( const IO_ERROR& 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
|
|
|
|
2008-01-29 22:09:09 +00:00
|
|
|
// copy the error string to safe place, ioe is in this scope only.
|
2016-09-14 22:36:45 +00:00
|
|
|
errorText = ioe.What();
|
2008-01-24 21:47:54 +00:00
|
|
|
}
|
|
|
|
|
2008-02-29 06:49:34 +00:00
|
|
|
// done assuredly, even if an exception was thrown and caught.
|
2009-01-05 05:21:35 +00:00
|
|
|
db.RevertMODULEs( GetBoard() );
|
2008-02-14 15:34:40 +00:00
|
|
|
|
2009-08-06 07:11:04 +00:00
|
|
|
// The two calls below to MODULE::Flip(), both set the
|
2008-02-07 20:23:58 +00:00
|
|
|
// 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 )
|
|
|
|
{
|
2011-02-11 20:48:13 +00:00
|
|
|
SetStatusText( wxString( _( "BOARD exported OK." ) ) );
|
2008-01-24 21:47:54 +00:00
|
|
|
}
|
|
|
|
else
|
2008-02-09 08:34:45 +00:00
|
|
|
{
|
2017-07-20 14:06:41 +00:00
|
|
|
DisplayErrorMessage( this,
|
|
|
|
_( "Unable to export, please fix and try again" ),
|
|
|
|
errorText );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
2014-03-27 17:45:05 +00:00
|
|
|
|
|
|
|
return ok;
|
2008-01-21 21:24:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace DSN {
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
const KICAD_T SPECCTRA_DB::scanPADs[] = { PCB_PAD_T, EOT };
|
2008-02-03 15:23:00 +00:00
|
|
|
|
2012-04-10 16:28:26 +00:00
|
|
|
// "specctra reported units" are what we tell the external router that our
|
|
|
|
// exported lengths are in.
|
|
|
|
|
2008-02-03 15:23:00 +00:00
|
|
|
|
2008-01-29 22:09:09 +00:00
|
|
|
/**
|
|
|
|
* Function scale
|
2012-04-10 16:28:26 +00:00
|
|
|
* converts a distance from PCBNEW internal units to the reported specctra dsn units
|
|
|
|
* in floating point format.
|
2008-01-29 22:09:09 +00:00
|
|
|
*/
|
2008-01-24 21:47:54 +00:00
|
|
|
static inline double scale( int kicadDist )
|
|
|
|
{
|
2012-04-11 14:49:11 +00:00
|
|
|
// nanometers to um
|
2012-04-26 21:34:20 +00:00
|
|
|
return kicadDist / ( IU_PER_MM / 1000.0 );
|
2012-04-10 16:28:26 +00:00
|
|
|
}
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
|
|
|
|
// / Convert integer internal units to float um
|
2012-04-10 16:28:26 +00:00
|
|
|
static inline double IU2um( int kicadDist )
|
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
return kicadDist * (1000.0 / IU_PER_MM);
|
2008-01-24 21:47:54 +00:00
|
|
|
}
|
|
|
|
|
2012-04-10 16:28:26 +00:00
|
|
|
|
2008-01-24 21:47:54 +00:00
|
|
|
static inline double mapX( int x )
|
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
return scale( x );
|
2008-01-24 21:47:54 +00:00
|
|
|
}
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-01-24 21:47:54 +00:00
|
|
|
static inline double mapY( int y )
|
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
return -scale( y ); // make y negative, since it is increasing going down.
|
2008-01-24 21:47:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-23 01:52:49 +00:00
|
|
|
/**
|
|
|
|
* Function mapPt
|
2011-09-30 18:15:37 +00:00
|
|
|
* converts a KiCad point into a DSN file point. Kicad's BOARD coordinates
|
2014-09-22 07:51:06 +00:00
|
|
|
* are in nanometers (called Internal Units or IU)and we are exporting in units
|
|
|
|
* of mils, so we have to scale them.
|
2008-01-23 01:52:49 +00:00
|
|
|
*/
|
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;
|
2013-04-30 15:25:41 +00:00
|
|
|
|
|
|
|
ret.x = mapX( pt.x );
|
|
|
|
ret.y = mapY( pt.y );
|
2008-01-29 22:09:09 +00:00
|
|
|
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-09 08:34:45 +00:00
|
|
|
/**
|
2008-03-12 16:24:38 +00:00
|
|
|
* Function isRoundKeepout
|
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.
|
|
|
|
*/
|
2008-03-12 16:24:38 +00:00
|
|
|
static bool isRoundKeepout( D_PAD* aPad )
|
2008-02-09 08:34:45 +00:00
|
|
|
{
|
2015-08-23 19:40:33 +00:00
|
|
|
if( aPad->GetShape()==PAD_SHAPE_CIRCLE )
|
2008-03-12 16:24:38 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
if( aPad->GetDrillSize().x >= aPad->GetSize().x )
|
2008-03-12 16:24:38 +00:00
|
|
|
return true;
|
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
if( !( aPad->GetLayerSet() & LSET::AllCuMask() ).any() )
|
2008-03-12 16:24:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2008-02-09 08:34:45 +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 )
|
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
PATH* path = new PATH( 0, T_path );
|
2008-01-25 22:03:36 +00:00
|
|
|
|
|
|
|
path->AppendPoint( aStart );
|
|
|
|
path->AppendPoint( aEnd );
|
|
|
|
path->SetLayerId( aLayerName.c_str() );
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
|
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
char name[256]; // padstack name builder
|
2008-02-14 01:07:52 +00:00
|
|
|
std::string uniqifier;
|
2008-01-29 16:45:14 +00:00
|
|
|
|
2008-02-20 19:13:20 +00:00
|
|
|
// caller must do these checks before calling here.
|
2008-03-12 16:24:38 +00:00
|
|
|
wxASSERT( !isRoundKeepout( aPad ) );
|
2008-01-29 16:45:14 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
PADSTACK* padstack = new PADSTACK();
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
int reportedLayers = 0; // how many in reported padstack
|
2014-06-24 16:17:18 +00:00
|
|
|
const char* layerName[MAX_CU_LAYERS];
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-11-10 20:54:26 +00:00
|
|
|
uniqifier = '[';
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2014-06-24 16:17:18 +00:00
|
|
|
static const LSET all_cu = LSET::AllCuMask();
|
|
|
|
|
|
|
|
bool onAllCopperLayers = ( (aPad->GetLayerSet() & all_cu) == all_cu );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-11-10 20:54:26 +00:00
|
|
|
if( onAllCopperLayers )
|
2013-04-30 15:25:41 +00:00
|
|
|
uniqifier += 'A'; // A for all layers
|
2008-02-12 02:09:39 +00:00
|
|
|
|
2008-11-10 20:54:26 +00:00
|
|
|
const int copperCount = aBoard->GetCopperLayerCount();
|
2017-03-20 14:18:15 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int layer=0; layer<copperCount; ++layer )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2017-03-13 03:19:33 +00:00
|
|
|
PCB_LAYER_ID kilayer = pcbLayer2kicad[layer];
|
2008-03-12 16:24:38 +00:00
|
|
|
|
2008-11-10 20:54:26 +00:00
|
|
|
if( onAllCopperLayers || aPad->IsOnLayer( kilayer ) )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2008-11-10 20:54:26 +00:00
|
|
|
layerName[reportedLayers++] = layerIds[layer].c_str();
|
2008-03-12 16:24:38 +00:00
|
|
|
|
2008-11-10 20:54:26 +00:00
|
|
|
if( !onAllCopperLayers )
|
2008-03-12 16:24:38 +00:00
|
|
|
{
|
2008-11-10 20:54:26 +00:00
|
|
|
if( layer == 0 )
|
|
|
|
uniqifier += 'T';
|
2013-04-30 15:25:41 +00:00
|
|
|
else if( layer == copperCount - 1 )
|
2008-11-10 20:54:26 +00:00
|
|
|
uniqifier += 'B';
|
|
|
|
else
|
2013-04-30 15:25:41 +00:00
|
|
|
uniqifier += char('0' + layer); // layer index char
|
2008-03-12 16:24:38 +00:00
|
|
|
}
|
|
|
|
}
|
2008-01-29 16:45:14 +00:00
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-11-10 20:54:26 +00:00
|
|
|
uniqifier += ']';
|
|
|
|
|
2008-02-20 19:13:20 +00:00
|
|
|
POINT dsnOffset;
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
if( aPad->GetOffset().x || aPad->GetOffset().y )
|
2008-02-20 19:13:20 +00:00
|
|
|
{
|
2011-11-24 17:32:51 +00:00
|
|
|
char offsetTxt[64];
|
2008-02-20 19:13:20 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
wxPoint offset( aPad->GetOffset().x, aPad->GetOffset().y );
|
2008-02-20 19:13:20 +00:00
|
|
|
|
|
|
|
dsnOffset = mapPt( offset );
|
|
|
|
|
|
|
|
// using '(' or ')' would cause padstack name to be quote wrapped,
|
|
|
|
// so use other brackets, and {} locks freerouter.
|
|
|
|
sprintf( offsetTxt, "[%.6g,%.6g]", dsnOffset.x, dsnOffset.y );
|
|
|
|
|
|
|
|
uniqifier += offsetTxt;
|
|
|
|
}
|
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
switch( aPad->GetShape() )
|
2008-02-05 02:13:16 +00:00
|
|
|
{
|
2015-08-23 19:40:33 +00:00
|
|
|
case PAD_SHAPE_CIRCLE:
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
double diameter = scale( aPad->GetSize().x );
|
2008-02-01 01:09:39 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int ndx=0; ndx<reportedLayers; ++ndx )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
SHAPE* shape = new SHAPE( padstack );
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
padstack->Append( shape );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
CIRCLE* circle = new CIRCLE( shape );
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
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-20 19:13:20 +00:00
|
|
|
circle->SetVertex( dsnOffset );
|
2008-02-14 01:07:52 +00:00
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-04-10 16:28:26 +00:00
|
|
|
snprintf( name, sizeof(name), "Round%sPad_%.6g_um",
|
2013-04-30 15:25:41 +00:00
|
|
|
uniqifier.c_str(), IU2um( aPad->GetSize().x ) );
|
2012-04-10 16:28:26 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
name[ sizeof(name) - 1 ] = 0;
|
2008-02-20 19:13:20 +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
|
|
|
|
2015-08-23 19:40:33 +00:00
|
|
|
case PAD_SHAPE_RECT:
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
double dx = scale( aPad->GetSize().x ) / 2.0;
|
|
|
|
double dy = scale( aPad->GetSize().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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
lowerLeft += dsnOffset;
|
|
|
|
upperRight += dsnOffset;
|
2008-02-20 19:13:20 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int ndx=0; ndx<reportedLayers; ++ndx )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
SHAPE* shape = new SHAPE( padstack );
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
padstack->Append( shape );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
RECTANGLE* rect = new RECTANGLE( shape );
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_um",
|
|
|
|
uniqifier.c_str(),
|
|
|
|
IU2um( aPad->GetSize().x ),
|
|
|
|
IU2um( aPad->GetSize().y ) );
|
2012-04-10 16:28:26 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
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
|
|
|
|
2015-08-23 19:40:33 +00:00
|
|
|
case PAD_SHAPE_OVAL:
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
double dx = scale( aPad->GetSize().x ) / 2.0;
|
|
|
|
double dy = scale( aPad->GetSize().y ) / 2.0;
|
|
|
|
double dr = dx - dy;
|
2008-02-20 19:13:20 +00:00
|
|
|
double radius;
|
2016-09-27 08:58:05 +00:00
|
|
|
POINT pstart;
|
|
|
|
POINT pstop;
|
2008-02-01 01:09:39 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
if( dr >= 0 ) // oval is horizontal
|
|
|
|
{
|
2008-02-20 19:13:20 +00:00
|
|
|
radius = dy;
|
|
|
|
|
2016-09-27 08:58:05 +00:00
|
|
|
pstart = POINT( -dr, 0.0 );
|
|
|
|
pstop = POINT( dr, 0.0 );
|
2008-02-14 01:07:52 +00:00
|
|
|
}
|
|
|
|
else // oval is vertical
|
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
radius = dx;
|
|
|
|
dr = -dr;
|
2008-02-01 01:09:39 +00:00
|
|
|
|
2016-09-27 08:58:05 +00:00
|
|
|
pstart = POINT( 0.0, -dr );
|
|
|
|
pstop = POINT( 0.0, dr );
|
2008-02-20 19:13:20 +00:00
|
|
|
}
|
|
|
|
|
2016-09-27 08:58:05 +00:00
|
|
|
pstart += dsnOffset;
|
|
|
|
pstop += dsnOffset;
|
2008-02-20 19:13:20 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int ndx=0; ndx<reportedLayers; ++ndx )
|
2008-02-20 19:13:20 +00:00
|
|
|
{
|
|
|
|
SHAPE* shape;
|
|
|
|
PATH* path;
|
|
|
|
// see http://www.freerouting.net/usren/viewtopic.php?f=3&t=317#p408
|
|
|
|
shape = new SHAPE( padstack );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-20 19:13:20 +00:00
|
|
|
padstack->Append( shape );
|
2016-09-27 08:58:05 +00:00
|
|
|
path = makePath( pstart, pstop, layerName[ndx] );
|
2008-02-20 19:13:20 +00:00
|
|
|
shape->SetShape( path );
|
|
|
|
path->aperture_width = 2.0 * radius;
|
2008-02-14 01:07:52 +00:00
|
|
|
}
|
2008-02-01 01:09:39 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_um",
|
|
|
|
uniqifier.c_str(),
|
|
|
|
IU2um( aPad->GetSize().x ),
|
|
|
|
IU2um( aPad->GetSize().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
|
|
|
|
2015-08-23 19:40:33 +00:00
|
|
|
case PAD_SHAPE_TRAPEZOID:
|
2010-09-07 15:46:55 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
double dx = scale( aPad->GetSize().x ) / 2.0;
|
|
|
|
double dy = scale( aPad->GetSize().y ) / 2.0;
|
2010-09-07 15:46:55 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
double ddx = scale( aPad->GetDelta().x ) / 2.0;
|
|
|
|
double ddy = scale( aPad->GetDelta().y ) / 2.0;
|
2010-09-07 15:46:55 +00:00
|
|
|
|
|
|
|
// see class_pad_draw_functions.cpp which draws the trapezoid pad
|
2010-09-07 17:04:39 +00:00
|
|
|
POINT lowerLeft( -dx - ddy, -dy - ddx );
|
|
|
|
POINT upperLeft( -dx + ddy, +dy + ddx );
|
|
|
|
POINT upperRight( +dx - ddy, +dy - ddx );
|
|
|
|
POINT lowerRight( +dx + ddy, -dy + ddx );
|
2010-09-07 15:46:55 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
lowerLeft += dsnOffset;
|
|
|
|
upperLeft += dsnOffset;
|
|
|
|
upperRight += dsnOffset;
|
|
|
|
lowerRight += dsnOffset;
|
2010-09-07 15:46:55 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int ndx=0; ndx<reportedLayers; ++ndx )
|
2010-09-07 15:46:55 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
SHAPE* shape = new SHAPE( padstack );
|
|
|
|
|
2010-09-07 15:46:55 +00:00
|
|
|
padstack->Append( shape );
|
|
|
|
|
|
|
|
// a T_polygon exists as a PATH
|
2013-04-30 15:25:41 +00:00
|
|
|
PATH* polygon = new PATH( shape, T_polygon );
|
|
|
|
|
2010-09-07 15:46:55 +00:00
|
|
|
shape->SetShape( polygon );
|
|
|
|
|
|
|
|
polygon->SetLayerId( layerName[ndx] );
|
|
|
|
|
|
|
|
polygon->AppendPoint( lowerLeft );
|
|
|
|
polygon->AppendPoint( upperLeft );
|
|
|
|
polygon->AppendPoint( upperRight );
|
|
|
|
polygon->AppendPoint( lowerRight );
|
|
|
|
}
|
|
|
|
|
|
|
|
// this string _must_ be unique for a given physical shape
|
2012-04-10 16:28:26 +00:00
|
|
|
snprintf( name, sizeof(name), "Trapz%sPad_%.6gx%.6g_%c%.6gx%c%.6g_um",
|
|
|
|
uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
|
2012-02-19 04:02:19 +00:00
|
|
|
aPad->GetDelta().x < 0 ? 'n' : 'p',
|
2012-08-11 05:50:17 +00:00
|
|
|
std::abs( IU2um( aPad->GetDelta().x )),
|
2012-02-19 04:02:19 +00:00
|
|
|
aPad->GetDelta().y < 0 ? 'n' : 'p',
|
2012-08-11 05:50:17 +00:00
|
|
|
std::abs( IU2um( aPad->GetDelta().y ) )
|
2010-09-07 15:46:55 +00:00
|
|
|
);
|
|
|
|
name[ sizeof(name)-1 ] = 0;
|
|
|
|
|
|
|
|
padstack->SetPadstackId( name );
|
|
|
|
}
|
2008-02-14 01:07:52 +00:00
|
|
|
break;
|
2018-02-02 11:55:11 +00:00
|
|
|
|
2018-08-29 07:13:07 +00:00
|
|
|
case PAD_SHAPE_CHAMFERED_RECT:
|
2018-02-03 17:50:55 +00:00
|
|
|
case PAD_SHAPE_ROUNDRECT:
|
|
|
|
{
|
|
|
|
// Export the shape as as polygon, round rect does not exist as primitive
|
|
|
|
const int circleToSegmentsCount = 36;
|
|
|
|
int rradius = aPad->GetRoundRectCornerRadius();
|
|
|
|
SHAPE_POLY_SET cornerBuffer;
|
|
|
|
// Use a slightly bigger shape because the round corners are approximated by
|
|
|
|
// segments, giving to the polygon a slightly smaller shape than the actual shape
|
|
|
|
|
|
|
|
/* calculates the coeff to compensate radius reduction of holes clearance
|
|
|
|
* due to the segment approx.
|
|
|
|
* For a circle the min radius is radius * cos( 2PI / s_CircleToSegmentsCount / 2)
|
2018-04-20 16:48:11 +00:00
|
|
|
* correctionFactor is cos( PI/s_CircleToSegmentsCount )
|
2018-02-03 17:50:55 +00:00
|
|
|
*/
|
2018-04-20 16:48:11 +00:00
|
|
|
double correctionFactor = cos( M_PI / (double) circleToSegmentsCount );
|
|
|
|
int extra_clearance = KiROUND( rradius * (1.0 - correctionFactor ) );
|
2018-02-03 17:50:55 +00:00
|
|
|
wxSize psize = aPad->GetSize();
|
|
|
|
psize.x += extra_clearance*2;
|
|
|
|
psize.y += extra_clearance*2;
|
|
|
|
rradius += extra_clearance;
|
2018-08-29 07:13:07 +00:00
|
|
|
bool doChamfer = aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT;
|
|
|
|
|
|
|
|
TransformRoundChamferedRectToPolygon( cornerBuffer, wxPoint(0,0), psize,
|
|
|
|
0, rradius,
|
|
|
|
aPad->GetChamferRectRatio(),
|
|
|
|
doChamfer ? aPad->GetChamferPositions() : 0,
|
2019-05-22 14:47:38 +00:00
|
|
|
aBoard->GetDesignSettings().m_MaxError );
|
2018-02-03 17:50:55 +00:00
|
|
|
SHAPE_LINE_CHAIN& polygonal_shape = cornerBuffer.Outline( 0 );
|
|
|
|
|
|
|
|
for( int ndx=0; ndx < reportedLayers; ++ndx )
|
|
|
|
{
|
|
|
|
SHAPE* shape = new SHAPE( padstack );
|
|
|
|
|
|
|
|
padstack->Append( shape );
|
|
|
|
|
|
|
|
// a T_polygon exists as a PATH
|
|
|
|
PATH* polygon = new PATH( shape, T_polygon );
|
|
|
|
|
|
|
|
shape->SetShape( polygon );
|
|
|
|
|
|
|
|
polygon->SetLayerId( layerName[ndx] );
|
|
|
|
// append a closed polygon
|
|
|
|
POINT first_corner;
|
|
|
|
|
|
|
|
for( int idx = 0; idx < polygonal_shape.PointCount(); idx++ )
|
|
|
|
{
|
2019-03-23 18:26:44 +00:00
|
|
|
POINT corner( scale( polygonal_shape.CPoint( idx ).x ),
|
|
|
|
scale( -polygonal_shape.CPoint( idx ).y ) );
|
2018-02-03 17:50:55 +00:00
|
|
|
corner += dsnOffset;
|
|
|
|
polygon->AppendPoint( corner );
|
|
|
|
|
|
|
|
if( idx == 0 )
|
|
|
|
first_corner = corner;
|
|
|
|
}
|
|
|
|
polygon->AppendPoint( first_corner ); // Close polygon
|
|
|
|
}
|
|
|
|
|
|
|
|
// this string _must_ be unique for a given physical shape
|
|
|
|
snprintf( name, sizeof(name), "RoundRect%sPad_%.6gx%.6g_%.6g_um",
|
|
|
|
uniqifier.c_str(),
|
|
|
|
IU2um( aPad->GetSize().x ),
|
|
|
|
IU2um( aPad->GetSize().y ), IU2um( rradius ) );
|
|
|
|
|
|
|
|
name[ sizeof(name) - 1 ] = 0;
|
|
|
|
|
|
|
|
padstack->SetPadstackId( name );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-02-02 11:55:11 +00:00
|
|
|
case PAD_SHAPE_CUSTOM:
|
|
|
|
{
|
2018-02-02 17:49:02 +00:00
|
|
|
std::vector<wxPoint> polygonal_shape;
|
2020-06-22 19:35:09 +00:00
|
|
|
SHAPE_POLY_SET pad_shape;
|
2020-08-12 21:18:13 +00:00
|
|
|
aPad->MergePrimitivesAsPolygon( &pad_shape, UNDEFINED_LAYER );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
2020-06-22 19:35:09 +00:00
|
|
|
#ifdef EXPORT_CUSTOM_PADS_CONVEX_HULL
|
2018-02-02 17:49:02 +00:00
|
|
|
BuildConvexHull( polygonal_shape, pad_shape );
|
2020-06-22 19:35:09 +00:00
|
|
|
#else
|
2018-02-02 17:49:02 +00:00
|
|
|
const SHAPE_LINE_CHAIN& p_outline = pad_shape.COutline( 0 );
|
2020-06-22 19:35:09 +00:00
|
|
|
|
2018-02-02 17:49:02 +00:00
|
|
|
for( int ii = 0; ii < p_outline.PointCount(); ++ii )
|
|
|
|
polygonal_shape.push_back( wxPoint( p_outline.CPoint( ii ) ) );
|
2020-06-22 19:35:09 +00:00
|
|
|
#endif
|
2018-02-02 17:49:02 +00:00
|
|
|
|
|
|
|
// The polygon must be closed
|
|
|
|
if( polygonal_shape.front() != polygonal_shape.back() )
|
|
|
|
polygonal_shape.push_back( polygonal_shape.front() );
|
|
|
|
|
|
|
|
for( int ndx=0; ndx < reportedLayers; ++ndx )
|
2018-02-02 11:55:11 +00:00
|
|
|
{
|
|
|
|
SHAPE* shape = new SHAPE( padstack );
|
|
|
|
|
|
|
|
padstack->Append( shape );
|
|
|
|
|
|
|
|
// a T_polygon exists as a PATH
|
|
|
|
PATH* polygon = new PATH( shape, T_polygon );
|
|
|
|
|
|
|
|
shape->SetShape( polygon );
|
|
|
|
|
|
|
|
polygon->SetLayerId( layerName[ndx] );
|
|
|
|
|
2018-02-03 17:50:55 +00:00
|
|
|
for( unsigned idx = 0; idx < polygonal_shape.size(); idx++ )
|
2018-02-02 11:55:11 +00:00
|
|
|
{
|
2018-02-02 17:49:02 +00:00
|
|
|
POINT corner( scale( polygonal_shape[idx].x ), scale( -polygonal_shape[idx].y ) );
|
2018-02-02 11:55:11 +00:00
|
|
|
corner += dsnOffset;
|
|
|
|
polygon->AppendPoint( corner );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this string _must_ be unique for a given physical shape, so try to make it unique
|
|
|
|
EDA_RECT rect = aPad->GetBoundingBox();
|
|
|
|
snprintf( name, sizeof(name), "Cust%sPad_%.6gx%.6g_%.6gx_%.6g_%d_um",
|
|
|
|
uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
|
|
|
|
IU2um( rect.GetWidth() ), IU2um( rect.GetHeight() ),
|
2018-02-02 17:49:02 +00:00
|
|
|
(int)polygonal_shape.size() );
|
2018-02-02 11:55:11 +00:00
|
|
|
name[ sizeof(name)-1 ] = 0;
|
|
|
|
|
|
|
|
padstack->SetPadstackId( name );
|
|
|
|
}
|
|
|
|
break;
|
2008-02-14 01:07:52 +00:00
|
|
|
}
|
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-29 06:49:34 +00:00
|
|
|
/// data type used to ensure unique-ness of pin names, holding (wxString and int)
|
2009-09-10 15:22:26 +00:00
|
|
|
typedef std::map<wxString, int> 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
|
|
|
{
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
PINMAP pinmap;
|
|
|
|
wxString padName;
|
|
|
|
|
|
|
|
PCB_TYPE_COLLECTOR moduleItems;
|
2008-01-24 21:47:54 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
// get all the MODULE's pads.
|
2008-02-22 17:34:11 +00:00
|
|
|
moduleItems.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
|
|
|
|
2013-09-08 18:31:21 +00:00
|
|
|
image->image_id = aModule->GetFPID().Format().c_str();
|
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.
|
2017-03-20 14:18:15 +00:00
|
|
|
for( int p=0; p < moduleItems.GetCount(); ++p )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2008-02-22 17:34:11 +00:00
|
|
|
D_PAD* pad = (D_PAD*) moduleItems[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
|
2008-03-12 16:24:38 +00:00
|
|
|
if( isRoundKeepout( pad ) )
|
2008-01-24 21:47:54 +00:00
|
|
|
{
|
2012-02-19 04:02:19 +00:00
|
|
|
double diameter = scale( pad->GetDrillSize().x );
|
|
|
|
POINT vertex = mapPt( pad->GetPos0() );
|
2008-01-24 21:47:54 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
int layerCount = aBoard->GetCopperLayerCount();
|
2017-03-20 14:18:15 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int layer=0; layer<layerCount; ++layer )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
KEEPOUT* keepout = new KEEPOUT( image, T_keepout );
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
image->keepouts.push_back( keepout );
|
2008-02-08 15:00:50 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
CIRCLE* circle = new CIRCLE( keepout );
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
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() );
|
|
|
|
}
|
|
|
|
}
|
2008-03-12 16:24:38 +00:00
|
|
|
// else if() could there be a square keepout here?
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
else
|
2008-02-08 15:00:50 +00:00
|
|
|
{
|
2017-03-20 14:18:15 +00:00
|
|
|
// Pads not on copper layers (i.e. only on tech layers) are ignored
|
|
|
|
// because they create invalid pads in .dsn file for freeroute
|
|
|
|
LSET mask_copper_layers = pad->GetLayerSet() & LSET::AllCuMask();
|
|
|
|
|
|
|
|
if( !mask_copper_layers.any() )
|
|
|
|
continue;
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
PADSTACK* padstack = makePADSTACK( aBoard, pad );
|
|
|
|
PADSTACKSET::iterator iter = padstackset.find( *padstack );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
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-20 19:13:20 +00:00
|
|
|
padstack = (PADSTACK*) *iter.base(); // folklore, 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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
PIN* pin = new PIN( image );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2017-08-11 09:22:13 +00:00
|
|
|
padName = pad->GetName();
|
2013-04-30 15:25:41 +00:00
|
|
|
pin->pin_id = TO_UTF8( padName );
|
2008-02-14 01:07:52 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2008-02-20 19:13:20 +00:00
|
|
|
else // pad name is a duplicate within this module
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
char buf[32];
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +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
|
|
|
|
2014-02-25 10:40:34 +00:00
|
|
|
pin->kiNetCode = pad->GetNetCode();
|
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
|
|
|
|
2016-05-02 10:49:14 +00:00
|
|
|
double angle = pad->GetOrientationDegrees() - aModule->GetOrientationDegrees();
|
|
|
|
NORMALIZE_ANGLE_DEGREES_POS( angle );
|
|
|
|
pin->SetRotation( angle );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2012-02-19 04:02:19 +00:00
|
|
|
wxPoint pos( pad->GetPos0() );
|
2008-01-24 21:47:54 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
pin->SetVertex( mapPt( pos ) );
|
2008-02-14 01:07:52 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
#if 1 // enable image (outline) scopes.
|
2011-10-01 19:24:27 +00:00
|
|
|
static const KICAD_T scanEDGEs[] = { PCB_MODULE_EDGE_T, EOT };
|
2008-02-22 17:34:11 +00:00
|
|
|
|
|
|
|
// get all the MODULE's EDGE_MODULEs and convert those to DSN outlines.
|
|
|
|
moduleItems.Collect( aModule, scanEDGEs );
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int i = 0; i<moduleItems.GetCount(); ++i )
|
2008-02-22 17:34:11 +00:00
|
|
|
{
|
|
|
|
EDGE_MODULE* graphic = (EDGE_MODULE*) moduleItems[i];
|
|
|
|
SHAPE* outline;
|
|
|
|
PATH* path;
|
|
|
|
|
2011-12-14 04:29:25 +00:00
|
|
|
switch( graphic->GetShape() )
|
2008-02-22 17:34:11 +00:00
|
|
|
{
|
|
|
|
case S_SEGMENT:
|
|
|
|
outline = new SHAPE( image, T_outline );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-22 17:34:11 +00:00
|
|
|
image->Append( outline );
|
|
|
|
path = new PATH( outline );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-22 17:34:11 +00:00
|
|
|
outline->SetShape( path );
|
2011-12-14 04:29:25 +00:00
|
|
|
path->SetAperture( scale( graphic->GetWidth() ) );
|
2008-02-22 17:34:11 +00:00
|
|
|
path->SetLayerId( "signal" );
|
2011-12-14 04:29:25 +00:00
|
|
|
path->AppendPoint( mapPt( graphic->GetStart0() ) );
|
|
|
|
path->AppendPoint( mapPt( graphic->GetEnd0() ) );
|
2008-02-22 17:34:11 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case S_CIRCLE:
|
|
|
|
{
|
|
|
|
// this is best done by 4 QARC's but freerouter does not yet support QARCs.
|
|
|
|
// for now, support by using line segments.
|
|
|
|
|
|
|
|
outline = new SHAPE( image, T_outline );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-22 17:34:11 +00:00
|
|
|
image->Append( outline );
|
|
|
|
path = new PATH( outline );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-22 17:34:11 +00:00
|
|
|
outline->SetShape( path );
|
2011-12-14 04:29:25 +00:00
|
|
|
path->SetAperture( scale( graphic->GetWidth() ) );
|
2008-02-22 17:34:11 +00:00
|
|
|
path->SetLayerId( "signal" );
|
|
|
|
|
2011-09-30 18:15:37 +00:00
|
|
|
// Do the math using KiCad units, that way we stay out of the
|
2008-02-29 06:49:34 +00:00
|
|
|
// scientific notation range of floating point numbers in the
|
|
|
|
// DSN file. We do not parse scientific notation in our own
|
|
|
|
// lexer/beautifier, and the spec is not clear that this is
|
|
|
|
// required. Fixed point floats are all that should be needed.
|
2008-02-22 17:34:11 +00:00
|
|
|
|
2013-05-01 17:32:36 +00:00
|
|
|
double radius = GetLineLength( graphic->GetStart(), graphic->GetEnd() );
|
2008-02-22 17:34:11 +00:00
|
|
|
|
2018-03-08 12:48:29 +00:00
|
|
|
// seg count to approximate circle by line segments
|
2018-03-22 18:02:45 +00:00
|
|
|
int seg_per_circle = GetArcToSegmentCount( radius, ARC_LOW_DEF, 360.0 );
|
2008-02-22 17:34:11 +00:00
|
|
|
|
2018-03-08 12:48:29 +00:00
|
|
|
for( int ii = 0; ii < seg_per_circle; ++ii )
|
2008-02-22 17:34:11 +00:00
|
|
|
{
|
2018-03-08 12:48:29 +00:00
|
|
|
double radians = 2*M_PI / seg_per_circle * ii;
|
2013-05-01 17:32:36 +00:00
|
|
|
wxPoint point( KiROUND( radius * cos( radians ) ),
|
|
|
|
KiROUND( radius * sin( radians ) ) );
|
2008-02-29 06:49:34 +00:00
|
|
|
|
|
|
|
point += graphic->m_Start0; // an offset
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
path->AppendPoint( mapPt( point ) );
|
2008-02-22 17:34:11 +00:00
|
|
|
}
|
2018-02-02 11:55:11 +00:00
|
|
|
// The shape must be closed
|
|
|
|
wxPoint point( radius , 0 );
|
|
|
|
point += graphic->m_Start0;
|
|
|
|
path->AppendPoint( mapPt( point ) );
|
2008-02-22 17:34:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case S_RECT:
|
|
|
|
case S_ARC:
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-03-01 13:15:41 +00:00
|
|
|
#endif
|
2008-02-22 17:34:11 +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,
|
2013-04-30 15:25:41 +00:00
|
|
|
int aTopLayer, int aBotLayer )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
|
|
|
char name[48];
|
|
|
|
PADSTACK* padstack = new PADSTACK();
|
2008-10-30 18:54:16 +00:00
|
|
|
double dsnDiameter = scale( aCopperDiameter );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
|
|
|
SHAPE* shape = new SHAPE( padstack );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
padstack->Append( shape );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
CIRCLE* circle = new CIRCLE( shape );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_um",
|
|
|
|
aTopLayer, aBotLayer, dsnDiameter,
|
|
|
|
// encode the drill value into the name for later import
|
|
|
|
IU2um( aDrillDiameter )
|
|
|
|
);
|
2009-11-02 05:20:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
name[ sizeof(name) - 1 ] = 0;
|
2008-02-14 01:07:52 +00:00
|
|
|
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
|
|
|
|
2014-04-25 06:00:04 +00:00
|
|
|
PADSTACK* SPECCTRA_DB::makeVia( const ::VIA* aVia )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2017-03-13 03:19:33 +00:00
|
|
|
PCB_LAYER_ID topLayerNum;
|
|
|
|
PCB_LAYER_ID botLayerNum;
|
2008-01-26 02:02:27 +00:00
|
|
|
|
* KIWAY Milestone A): Make major modules into DLL/DSOs.
! The initial testing of this commit should be done using a Debug build so that
all the wxASSERT()s are enabled. Also, be sure and keep enabled the
USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it
off is senseless anyways. If you want stable code, go back to a prior version,
the one tagged with "stable".
* Relocate all functionality out of the wxApp derivative into more finely
targeted purposes:
a) DLL/DSO specific
b) PROJECT specific
c) EXE or process specific
d) configuration file specific data
e) configuration file manipulations functions.
All of this functionality was blended into an extremely large wxApp derivative
and that was incompatible with the desire to support multiple concurrently
loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects.
An amazing amount of organization come from simply sorting each bit of
functionality into the proper box.
* Switch to wxConfigBase from wxConfig everywhere except instantiation.
* Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD,
PGM_SINGLE_TOP,
* Remove "Return" prefix on many function names.
* Remove obvious comments from CMakeLists.txt files, and from else() and endif()s.
* Fix building boost for use in a DSO on linux.
* Remove some of the assumptions in the CMakeLists.txt files that windows had
to be the host platform when building windows binaries.
* Reduce the number of wxStrings being constructed at program load time via
static construction.
* Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that
these functions are useful even when the wxConfigBase comes from another
source, as is the case in the KICAD_MANAGER_FRAME.
* Move the setting of the KIPRJMOD environment variable into class PROJECT,
so that it can be moved into a project variable soon, and out of FP_LIB_TABLE.
* Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all
its child wxFrames and wxDialogs now have a Kiway() member function which
returns a KIWAY& that that window tree branch is in support of. This is like
wxWindows DNA in that child windows get this member with proper value at time
of construction.
* Anticipate some of the needs for milestones B) and C) and make code
adjustments now in an effort to reduce work in those milestones.
* No testing has been done for python scripting, since milestone C) has that
being largely reworked and re-thought-out.
2014-03-20 00:42:08 +00:00
|
|
|
aVia->LayerPair( &topLayerNum, &botLayerNum );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
int topLayer = kicadLayer2pcb[topLayerNum];
|
|
|
|
int botLayer = kicadLayer2pcb[botLayerNum];
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
if( topLayer > botLayer )
|
2015-06-26 13:41:56 +00:00
|
|
|
std::swap( topLayer, botLayer );
|
2008-02-14 01:07:52 +00:00
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
return makeVia( aVia->GetWidth(), aVia->GetDrillValue(), topLayer, botLayer );
|
2008-01-21 22:16:45 +00:00
|
|
|
}
|
2008-01-22 20:48:02 +00:00
|
|
|
|
2008-05-05 19:47:38 +00:00
|
|
|
|
2015-02-17 18:47:21 +00:00
|
|
|
void SPECCTRA_DB::fillBOUNDARY( BOARD* aBoard, BOUNDARY* boundary )
|
2008-05-05 19:47:38 +00:00
|
|
|
{
|
2017-03-20 13:55:32 +00:00
|
|
|
wxString errMessage;
|
|
|
|
SHAPE_POLY_SET outlines;
|
2008-05-05 19:47:38 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
aBoard->GetBoardPolygonOutlines( outlines, &errMessage );
|
2008-05-05 19:47:38 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
for( int cnt = 0; cnt < outlines.OutlineCount(); cnt++ ) // Should be one outline
|
2008-05-05 19:47:38 +00:00
|
|
|
{
|
|
|
|
PATH* path = new PATH( boundary );
|
|
|
|
boundary->paths.push_back( path );
|
|
|
|
path->layer_id = "pcb";
|
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
SHAPE_LINE_CHAIN& outline = outlines.Outline( cnt );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2017-03-20 13:55:32 +00:00
|
|
|
for( int ii = 0; ii < outline.PointCount(); ii++ )
|
2013-04-30 15:25:41 +00:00
|
|
|
{
|
2019-03-23 18:26:44 +00:00
|
|
|
wxPoint pos( outline.CPoint( ii ).x, outline.CPoint( ii ).y );
|
2017-03-20 13:55:32 +00:00
|
|
|
path->AppendPoint( mapPt( pos ) );
|
2008-05-05 19:47:38 +00:00
|
|
|
}
|
2010-04-01 15:00:47 +00:00
|
|
|
|
2017-03-20 13:55:32 +00:00
|
|
|
// Close polygon:
|
2019-03-23 18:26:44 +00:00
|
|
|
wxPoint pos0( outline.CPoint( 0 ).x, outline.CPoint( 0 ).y );
|
2017-03-22 09:58:14 +00:00
|
|
|
path->AppendPoint( mapPt( pos0 ) );
|
2008-05-05 20:13:54 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
// Generate holes as keepout:
|
|
|
|
for( int ii = 0; ii < outlines.HoleCount( cnt ); ii++ )
|
|
|
|
{
|
|
|
|
// emit a signal layers keepout for every interior polygon left...
|
|
|
|
KEEPOUT* keepout = new KEEPOUT( NULL, T_keepout );
|
|
|
|
PATH* poly_ko = new PATH( NULL, T_polygon );
|
2008-05-05 19:47:38 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
keepout->SetShape( poly_ko );
|
|
|
|
poly_ko->SetLayerId( "signal" );
|
|
|
|
pcb->structure->keepouts.push_back( keepout );
|
2013-10-04 08:42:09 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
SHAPE_LINE_CHAIN& hole = outlines.Hole( cnt, ii );
|
2013-10-04 08:42:09 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
for( int jj = 0; jj < hole.PointCount(); jj++ )
|
|
|
|
{
|
2019-03-23 18:26:44 +00:00
|
|
|
wxPoint pos( hole.CPoint( jj ).x, hole.CPoint( jj ).y );
|
2017-03-22 09:58:14 +00:00
|
|
|
poly_ko->AppendPoint( mapPt( pos ) );
|
|
|
|
}
|
2015-07-27 19:45:57 +00:00
|
|
|
|
2017-03-22 09:58:14 +00:00
|
|
|
// Close polygon:
|
2019-03-23 18:26:44 +00:00
|
|
|
wxPoint pos( hole.CPoint( 0 ).x, hole.CPoint( 0 ).y );
|
2017-03-20 13:55:32 +00:00
|
|
|
poly_ko->AppendPoint( mapPt( pos ) );
|
2013-10-04 08:42:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-20 13:55:32 +00:00
|
|
|
if( !errMessage.IsEmpty() )
|
|
|
|
wxLogMessage( errMessage );
|
2013-10-04 08:42:09 +00:00
|
|
|
}
|
|
|
|
|
2008-05-05 19:47:38 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
typedef std::set<std::string> STRINGSET;
|
|
|
|
typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
|
2008-02-14 01:07:52 +00:00
|
|
|
|
|
|
|
|
2015-02-17 18:47:21 +00:00
|
|
|
void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
2008-01-22 20:48:02 +00:00
|
|
|
{
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
PCB_TYPE_COLLECTOR items;
|
2008-01-22 20:48:02 +00:00
|
|
|
|
2011-10-01 19:24:27 +00:00
|
|
|
static const KICAD_T scanMODULEs[] = { PCB_MODULE_T, 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-05-06 12:32:41 +00:00
|
|
|
// back to us later from the router.
|
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 )
|
|
|
|
{
|
2017-12-24 15:04:02 +00:00
|
|
|
THROW_IO_ERROR( wxString::Format( _( "Symbol with value of \"%s\" has empty reference id." ),
|
2015-12-10 08:13:35 +00:00
|
|
|
GetChars( module->GetValue() ) ) );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// if we cannot insert OK, that means the reference has been seen before.
|
2011-02-02 15:31:48 +00:00
|
|
|
STRINGSET_PAIR refpair = refs.insert( TO_UTF8( module->GetReference() ) );
|
2008-02-14 01:07:52 +00:00
|
|
|
if( !refpair.second ) // insert failed
|
2008-02-09 08:34:45 +00:00
|
|
|
{
|
2017-12-24 15:04:02 +00:00
|
|
|
THROW_IO_ERROR( wxString::Format( _( "Multiple symbols have identical reference IDs of \"%s\"." ),
|
2015-12-10 08:13:35 +00:00
|
|
|
GetChars( module->GetReference() ) ) );
|
2008-02-09 08:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-01-22 20:48:02 +00:00
|
|
|
if( !pcb )
|
|
|
|
pcb = SPECCTRA_DB::MakePCB();
|
|
|
|
|
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.
|
2011-09-30 18:15:37 +00:00
|
|
|
// @question : why does KiCad not display layers in that order?
|
2008-01-31 06:46:31 +00:00
|
|
|
|
2008-02-08 00:16:59 +00:00
|
|
|
buildLayerMaps( aBoard );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-08 00:16:59 +00:00
|
|
|
int layerCount = aBoard->GetCopperLayerCount();
|
2008-01-31 01:30:52 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int pcbNdx=0; pcbNdx<layerCount; ++pcbNdx )
|
2008-02-08 00:16:59 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
LAYER* layer = new LAYER( pcb->structure );
|
|
|
|
|
2008-01-31 01:30:52 +00:00
|
|
|
pcb->structure->layers.push_back( layer );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-08 00:16:59 +00:00
|
|
|
layer->name = layerIds[pcbNdx];
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-03-04 04:22:27 +00:00
|
|
|
DSN_T layerType;
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-03-04 04:22:27 +00:00
|
|
|
switch( aBoard->GetLayerType( pcbLayer2kicad[pcbNdx] ) )
|
|
|
|
{
|
|
|
|
default:
|
2014-01-20 19:11:42 +00:00
|
|
|
case LT_SIGNAL: layerType = T_signal; break;
|
|
|
|
case LT_POWER: layerType = T_power; break;
|
|
|
|
|
|
|
|
#if 1 // Freerouter does not support type "mixed", only signal and power.
|
|
|
|
// Remap "mixed" to "signal".
|
|
|
|
case LT_MIXED: layerType = T_signal; break;
|
|
|
|
#else
|
|
|
|
case LT_MIXED: layerType = T_mixed; break;
|
|
|
|
#endif
|
|
|
|
case LT_JUMPER: layerType = T_jumper; break;
|
2008-03-04 04:22:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
layer->layer_type = layerType;
|
|
|
|
|
2008-02-05 02:13:16 +00:00
|
|
|
layer->properties.push_back( PROPERTY() );
|
2013-04-30 15:25:41 +00:00
|
|
|
PROPERTY* property = &layer->properties.back();
|
2008-02-05 02:13:16 +00:00
|
|
|
property->name = "index";
|
2013-04-30 15:25:41 +00:00
|
|
|
char temp[32];
|
2008-02-05 02:13:16 +00:00
|
|
|
sprintf( temp, "%d", pcbNdx );
|
2008-02-07 20:23:58 +00:00
|
|
|
property->value = temp;
|
2008-01-31 01:30:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-29 22:09:09 +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
|
|
|
{
|
2012-04-11 14:49:11 +00:00
|
|
|
// tell freerouter to use "tenths of micrometers",
|
|
|
|
// which is 100 nm resolution. Possibly more resolution is possible
|
|
|
|
// in freerouter, but it would need testing.
|
2012-04-10 16:28:26 +00:00
|
|
|
|
|
|
|
pcb->unit->units = T_um;
|
2013-04-30 15:25:41 +00:00
|
|
|
pcb->resolution->units = T_um;
|
|
|
|
pcb->resolution->value = 10; // tenths of a um
|
2012-04-11 14:49:11 +00:00
|
|
|
// pcb->resolution->value = 1000; // "thousandths of a um" (i.e. "nm")
|
2008-01-23 01:52:49 +00:00
|
|
|
}
|
2008-01-22 20:48:02 +00:00
|
|
|
|
2008-01-23 01:52:49 +00:00
|
|
|
//-----<boundary_descriptor>------------------------------------------
|
2008-01-22 20:48:02 +00:00
|
|
|
{
|
2008-07-30 17:24:13 +00:00
|
|
|
// Because fillBOUNDARY() can throw an exception, we link in an
|
2008-05-05 19:47:38 +00:00
|
|
|
// empty boundary so the BOUNDARY does not get lost in the event of
|
|
|
|
// of an exception.
|
2013-04-30 15:25:41 +00:00
|
|
|
BOUNDARY* boundary = new BOUNDARY( 0 );
|
|
|
|
|
2008-05-05 19:47:38 +00:00
|
|
|
pcb->structure->SetBOUNDARY( boundary );
|
|
|
|
fillBOUNDARY( aBoard, 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>--------------------------------------------------------
|
|
|
|
{
|
2020-05-18 00:20:16 +00:00
|
|
|
char rule[80];
|
|
|
|
NETCLASS* defaultClass = aBoard->GetDesignSettings().GetDefault();
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2020-05-18 00:20:16 +00:00
|
|
|
int defaultTrackWidth = defaultClass->GetTrackWidth();
|
|
|
|
int defaultClearance = defaultClass->GetClearance();
|
2008-10-23 21:06:43 +00:00
|
|
|
|
2020-05-18 00:20:16 +00:00
|
|
|
double clearance = scale( defaultClearance );
|
2008-02-09 16:33:03 +00:00
|
|
|
|
2020-05-18 00:20:16 +00:00
|
|
|
STRINGS& rules = pcb->structure->rules->rules;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
sprintf( rule, "(width %.6g)", scale( defaultTrackWidth ) );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
sprintf( rule, "(clearance %.6g)", clearance + safetyMargin );
|
2008-10-23 21:06:43 +00:00
|
|
|
rules.push_back( rule );
|
|
|
|
|
2009-11-13 14:37:37 +00:00
|
|
|
// On a high density board (a board with 4 mil tracks, 4 mil spacing)
|
|
|
|
// a typical solder mask clearance will be 2-3 mils.
|
2008-10-29 23:57:04 +00:00
|
|
|
// This exposes 2 to 3 mils of bare board around each pad, and would
|
|
|
|
// leave only 1 to 2 mils of solder mask between the solder mask's boundary
|
|
|
|
// to the edge of any trace within "clearance" of the pad. So we need at least
|
|
|
|
// 2 mils *extra* clearance for traces which would come near a pad on
|
2008-10-23 21:06:43 +00:00
|
|
|
// a different net. So if the baseline trace to trace clearance was say 4 mils, then
|
2009-11-13 14:37:37 +00:00
|
|
|
// the SMD to trace clearance should be at least 6 mils.
|
|
|
|
double default_smd = clearance + safetyMargin;
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2009-11-13 14:37:37 +00:00
|
|
|
if( default_smd <= 6.0 )
|
|
|
|
default_smd = 6.0;
|
|
|
|
|
|
|
|
sprintf( rule, "(clearance %.6g (type default_smd))", default_smd );
|
|
|
|
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-03-31 13:45:36 +00:00
|
|
|
/* see: http://www.freerouting.net/usren/viewtopic.php?f=5&t=339#p474
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type pad_to_turn_gap))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type smd_to_turn_gap))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type via_via))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type via_smd))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type via_pin))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type pin_pin))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
sprintf( rule, "(clearance %.6g (type smd_pin))", clearance + safetyMargin );
|
2008-01-31 06:46:31 +00:00
|
|
|
rules.push_back( rule );
|
2008-03-31 13:45:36 +00:00
|
|
|
*/
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-10-23 21:06:43 +00:00
|
|
|
// Pad to pad spacing on a single SMT part can be closer than our
|
|
|
|
// clearance, we don't want freerouter complaining about that, so
|
|
|
|
// output a significantly smaller pad to pad clearance to freerouter.
|
2013-04-30 15:25:41 +00:00
|
|
|
clearance = scale( defaultClearance ) / 4;
|
2008-02-09 16:33:03 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
2012-07-14 16:27:25 +00:00
|
|
|
//-----<zone containers (not keepout areas) become planes>--------------------------------
|
|
|
|
// Note: only zones are output here, keepout areas be be created later
|
2008-01-23 22:36:37 +00:00
|
|
|
{
|
2009-02-07 16:06:55 +00:00
|
|
|
int netlessZones = 0;
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
|
2008-01-23 22:36:37 +00:00
|
|
|
items.Collect( aBoard, scanZONEs );
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int i = 0; i<items.GetCount(); ++i )
|
2008-01-23 22:36:37 +00:00
|
|
|
{
|
|
|
|
ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
|
|
|
|
|
2020-09-21 23:32:07 +00:00
|
|
|
if( item->GetIsRuleArea() )
|
2012-07-14 16:27:25 +00:00
|
|
|
continue;
|
|
|
|
|
2014-06-16 12:04:55 +00:00
|
|
|
// Currently, we export only copper layers
|
|
|
|
if( ! IsCopperLayer( item->GetLayer() ) )
|
|
|
|
continue;
|
|
|
|
|
2008-01-23 22:36:37 +00:00
|
|
|
COPPER_PLANE* plane = new COPPER_PLANE( pcb->structure );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-05-22 15:55:24 +00:00
|
|
|
pcb->structure->planes.push_back( plane );
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
PATH* mainPolygon = new PATH( plane, T_polygon );
|
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
plane->SetShape( mainPolygon );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2014-01-14 10:41:06 +00:00
|
|
|
plane->name = TO_UTF8( item->GetNetname() );
|
2008-01-31 01:30:52 +00:00
|
|
|
|
2009-02-07 16:06:55 +00:00
|
|
|
if( plane->name.size() == 0 )
|
|
|
|
{
|
|
|
|
char name[32];
|
|
|
|
|
|
|
|
// This is one of those no connection zones, netcode=0, and it has no name.
|
|
|
|
// Create a unique, bogus netname.
|
|
|
|
NET* no_net = new NET( pcb->network );
|
|
|
|
|
|
|
|
sprintf( name, "@:no_net_%d", netlessZones++ );
|
|
|
|
no_net->net_id = name;
|
|
|
|
|
|
|
|
// add the bogus net name to network->nets.
|
|
|
|
pcb->network->nets.push_back( no_net );
|
|
|
|
|
|
|
|
// use the bogus net name in the netless zone.
|
|
|
|
plane->name = no_net->net_id;
|
|
|
|
}
|
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
mainPolygon->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
// Handle the main outlines
|
|
|
|
SHAPE_POLY_SET::ITERATOR iterator;
|
2018-02-02 11:55:11 +00:00
|
|
|
wxPoint startpoint;
|
|
|
|
bool is_first_point = true;
|
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
for( iterator = item->IterateWithHoles(); iterator; iterator++ )
|
2008-01-23 22:36:37 +00:00
|
|
|
{
|
2017-03-07 12:06:00 +00:00
|
|
|
wxPoint point( iterator->x, iterator->y );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
|
|
|
if( is_first_point )
|
|
|
|
{
|
|
|
|
startpoint = point;
|
|
|
|
is_first_point = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mainPolygon->AppendPoint( mapPt( point ) );
|
2009-02-06 14:23:56 +00:00
|
|
|
|
|
|
|
// this was the end of the main polygon
|
2017-03-07 12:06:00 +00:00
|
|
|
if( iterator.IsEndContour() )
|
2018-02-02 11:55:11 +00:00
|
|
|
{
|
|
|
|
// Close polygon
|
|
|
|
mainPolygon->AppendPoint( mapPt( startpoint ) );
|
2009-02-06 14:23:56 +00:00
|
|
|
break;
|
2018-02-02 11:55:11 +00:00
|
|
|
}
|
2009-02-06 14:23:56 +00:00
|
|
|
}
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
WINDOW* window = 0;
|
|
|
|
PATH* cutout = 0;
|
2009-02-06 14:23:56 +00:00
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
bool isStartContour = true;
|
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
// handle the cutouts
|
2017-03-07 12:06:00 +00:00
|
|
|
for( iterator++; iterator; iterator++ )
|
2009-02-06 14:23:56 +00:00
|
|
|
{
|
2017-03-07 12:06:00 +00:00
|
|
|
if( isStartContour )
|
2009-02-06 14:23:56 +00:00
|
|
|
{
|
2018-02-02 11:55:11 +00:00
|
|
|
is_first_point = true;
|
2009-02-06 14:23:56 +00:00
|
|
|
window = new WINDOW( plane );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
plane->AddWindow( window );
|
|
|
|
|
2009-02-06 22:10:37 +00:00
|
|
|
cutout = new PATH( window, T_polygon );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
window->SetShape( cutout );
|
|
|
|
|
|
|
|
cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
|
|
|
|
}
|
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
// If the point in this iteration is the last of the contour, the next iteration
|
|
|
|
// will start with a new contour.
|
|
|
|
isStartContour = iterator.IsEndContour();
|
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
wxASSERT( window );
|
|
|
|
wxASSERT( cutout );
|
|
|
|
|
2017-03-07 12:06:00 +00:00
|
|
|
wxPoint point(iterator->x, iterator->y );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
|
|
|
if( is_first_point )
|
|
|
|
{
|
|
|
|
startpoint = point;
|
|
|
|
is_first_point = false;
|
|
|
|
}
|
|
|
|
|
2009-02-06 14:23:56 +00:00
|
|
|
cutout->AppendPoint( mapPt(point) );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
|
|
|
// Close the polygon
|
|
|
|
if( iterator.IsEndContour() )
|
|
|
|
cutout->AppendPoint( mapPt( startpoint ) );
|
2008-01-23 22:36:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-24 21:47:54 +00:00
|
|
|
|
2012-07-14 16:27:25 +00:00
|
|
|
//-----<zone containers flagged keepout areas become keepout>--------------------------------
|
|
|
|
{
|
|
|
|
static const KICAD_T scanZONEs[] = { PCB_ZONE_AREA_T, EOT };
|
|
|
|
items.Collect( aBoard, scanZONEs );
|
|
|
|
|
|
|
|
for( int i=0; i<items.GetCount(); ++i )
|
|
|
|
{
|
|
|
|
ZONE_CONTAINER* item = (ZONE_CONTAINER*) items[i];
|
|
|
|
|
2020-09-21 23:32:07 +00:00
|
|
|
if( !item->GetIsRuleArea() )
|
2012-07-14 16:27:25 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// keepout areas have a type. types are
|
|
|
|
// T_place_keepout, T_via_keepout, T_wire_keepout,
|
|
|
|
// T_bend_keepout, T_elongate_keepout, T_keepout.
|
|
|
|
// Pcbnew knows only T_keepout, T_via_keepout and T_wire_keepout
|
|
|
|
DSN_T keepout_type;
|
|
|
|
|
|
|
|
if( item->GetDoNotAllowVias() && item->GetDoNotAllowTracks() )
|
|
|
|
keepout_type = T_keepout;
|
|
|
|
else if( item->GetDoNotAllowVias() )
|
|
|
|
keepout_type = T_via_keepout;
|
|
|
|
else if( item->GetDoNotAllowTracks() )
|
|
|
|
keepout_type = T_wire_keepout;
|
|
|
|
else
|
|
|
|
keepout_type = T_keepout;
|
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
// Now, build keepout polygon on each copper layer where the item
|
|
|
|
// keepout is living (keepout zones can live on many copper layers)
|
|
|
|
const int copperCount = aBoard->GetCopperLayerCount();
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
for( int layer = 0; layer < copperCount; layer++ )
|
|
|
|
{
|
|
|
|
if( layer == copperCount-1)
|
|
|
|
layer = B_Cu;
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
if( !item->IsOnLayer( PCB_LAYER_ID( layer ) ) )
|
|
|
|
continue;
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
KEEPOUT* keepout = new KEEPOUT( pcb->structure, keepout_type );
|
|
|
|
pcb->structure->keepouts.push_back( keepout );
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
PATH* mainPolygon = new PATH( keepout, T_polygon );
|
|
|
|
keepout->SetShape( mainPolygon );
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
mainPolygon->layer_id = layerIds[ kicadLayer2pcb[ layer ] ];
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
// Handle the main outlines
|
|
|
|
SHAPE_POLY_SET::ITERATOR iterator;
|
2018-02-02 11:55:11 +00:00
|
|
|
bool is_first_point = true;
|
|
|
|
wxPoint startpoint;
|
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
for( iterator = item->IterateWithHoles(); iterator; iterator++ )
|
|
|
|
{
|
|
|
|
wxPoint point( iterator->x, iterator->y );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
|
|
|
if( is_first_point )
|
|
|
|
{
|
|
|
|
startpoint = point;
|
|
|
|
is_first_point = false;
|
|
|
|
}
|
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
mainPolygon->AppendPoint( mapPt(point) );
|
2017-03-07 12:06:00 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
// this was the end of the main polygon
|
|
|
|
if( iterator.IsEndContour() )
|
2018-02-02 11:55:11 +00:00
|
|
|
{
|
|
|
|
mainPolygon->AppendPoint( mapPt( startpoint ) );
|
2017-10-31 18:53:35 +00:00
|
|
|
break;
|
2018-02-02 11:55:11 +00:00
|
|
|
}
|
2017-10-31 18:53:35 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 11:55:11 +00:00
|
|
|
WINDOW* window = nullptr;
|
|
|
|
PATH* cutout = nullptr;
|
2017-10-31 18:53:35 +00:00
|
|
|
|
|
|
|
bool isStartContour = true;
|
|
|
|
|
|
|
|
// handle the cutouts
|
|
|
|
for( iterator++; iterator; iterator++ )
|
2012-07-14 16:27:25 +00:00
|
|
|
{
|
2017-10-31 18:53:35 +00:00
|
|
|
if( isStartContour )
|
|
|
|
{
|
2018-02-02 11:55:11 +00:00
|
|
|
is_first_point = true;
|
2017-10-31 18:53:35 +00:00
|
|
|
window = new WINDOW( keepout );
|
|
|
|
keepout->AddWindow( window );
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
cutout = new PATH( window, T_polygon );
|
2017-03-07 12:06:00 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
window->SetShape( cutout );
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
cutout->layer_id = layerIds[ kicadLayer2pcb[ item->GetLayer() ] ];
|
|
|
|
}
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
isStartContour = iterator.IsEndContour();
|
2017-03-07 12:06:00 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
wxASSERT( window );
|
|
|
|
wxASSERT( cutout );
|
2012-07-14 16:27:25 +00:00
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
wxPoint point(iterator->x, iterator->y );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
|
|
|
if( is_first_point )
|
|
|
|
{
|
|
|
|
startpoint = point;
|
|
|
|
is_first_point = false;
|
|
|
|
}
|
|
|
|
|
2017-10-31 18:53:35 +00:00
|
|
|
cutout->AppendPoint( mapPt(point) );
|
2018-02-02 11:55:11 +00:00
|
|
|
|
|
|
|
// Close the polygon
|
|
|
|
if( iterator.IsEndContour() )
|
|
|
|
cutout->AppendPoint( mapPt( startpoint ) );
|
2017-10-31 18:53:35 +00:00
|
|
|
}
|
2012-07-14 16:27:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
PIN_REF empty( pcb->network );
|
|
|
|
|
2008-02-29 06:49:34 +00:00
|
|
|
std::string componentId;
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
// find the highest numbered netCode within the board.
|
2011-12-10 05:33:24 +00:00
|
|
|
int highestNetCode = aBoard->GetNetCount() - 1;
|
2013-04-30 15:25:41 +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
|
2013-04-30 15:25:41 +00:00
|
|
|
nets.resize( highestNetCode + 1, NULL );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2018-09-21 12:41:28 +00:00
|
|
|
for( unsigned i = 1 /* skip "No Net" at [0] */; i < nets.size(); ++i )
|
2008-02-14 01:07:52 +00:00
|
|
|
nets[i] = new NET( pcb->network );
|
2008-01-29 16:45:14 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( unsigned ii = 0; ii < aBoard->GetNetCount(); ii++ )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
NETINFO_ITEM* net = aBoard->FindNet( ii );
|
|
|
|
int netcode = net->GetNet();
|
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
if( netcode > 0 )
|
2011-02-02 15:31:48 +00:00
|
|
|
nets[ netcode ]->net_id = TO_UTF8( net->GetNetname() );
|
2008-02-14 01:07:52 +00:00
|
|
|
}
|
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();
|
|
|
|
|
2013-04-30 15:25:41 +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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
IMAGE* image = makeIMAGE( aBoard, module );
|
2008-02-14 01:07:52 +00:00
|
|
|
|
2011-02-02 15:31:48 +00:00
|
|
|
componentId = TO_UTF8( module->GetReference() );
|
2008-02-29 06:49:34 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
// 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
|
2008-02-29 06:49:34 +00:00
|
|
|
// of pin names within a module, do not move this code because
|
|
|
|
// the life of this 'IMAGE* image' is not necessarily long. The
|
2008-02-14 01:07:52 +00:00
|
|
|
// 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!
|
2013-04-30 15:25:41 +00:00
|
|
|
for( unsigned p = 0; p<image->pins.size(); ++p )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
PIN* pin = &image->pins[p];
|
|
|
|
|
|
|
|
int netcode = pin->kiNetCode;
|
2008-02-14 01:07:52 +00:00
|
|
|
|
|
|
|
if( netcode > 0 )
|
|
|
|
{
|
|
|
|
NET* net = nets[netcode];
|
|
|
|
|
|
|
|
net->pins.push_back( empty );
|
|
|
|
|
|
|
|
PIN_REF& pin_ref = net->pins.back();
|
|
|
|
|
2008-02-29 06:49:34 +00:00
|
|
|
pin_ref.component_id = componentId;
|
2008-02-14 01:07:52 +00:00
|
|
|
pin_ref.pin_id = pin->pin_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-29 16:45:14 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
IMAGE* registered = pcb->library->LookupIMAGE( image );
|
|
|
|
|
2008-01-29 22:09:09 +00:00
|
|
|
if( registered != image )
|
2008-01-24 21:47:54 +00:00
|
|
|
{
|
2008-01-29 22:09:09 +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-01-29 22:09:09 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() );
|
|
|
|
|
|
|
|
PLACE* place = new PLACE( comp );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-01-29 22:09:09 +00:00
|
|
|
comp->places.push_back( place );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2016-05-02 10:49:14 +00:00
|
|
|
place->SetRotation( module->GetOrientationDegrees() );
|
2013-03-13 18:53:58 +00:00
|
|
|
place->SetVertex( mapPt( module->GetPosition() ) );
|
2008-02-29 06:49:34 +00:00
|
|
|
place->component_id = componentId;
|
2011-02-02 15:31:48 +00:00
|
|
|
place->part_number = TO_UTF8( module->GetValue() );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-01-29 22:09:09 +00:00
|
|
|
// module is flipped from bottom side, set side to T_back
|
2013-03-13 18:53:58 +00:00
|
|
|
if( module->GetFlag() )
|
2008-02-05 02:13:16 +00:00
|
|
|
{
|
2016-05-02 10:49:14 +00:00
|
|
|
double angle = 180.0 - module->GetOrientationDegrees();
|
|
|
|
NORMALIZE_ANGLE_DEGREES_POS( angle );
|
|
|
|
place->SetRotation( angle );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-01-29 22:09:09 +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
|
2013-04-30 15:25:41 +00:00
|
|
|
for( PADSTACKSET::iterator i = padstackset.begin(); i!=padstackset.end();
|
|
|
|
i = padstackset.begin() )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
|
|
|
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
|
2013-04-30 15:25:41 +00:00
|
|
|
for( unsigned n = 1; n<nets.size(); ++n )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
|
|
|
NET* net = nets[n];
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-29 06:49:34 +00:00
|
|
|
if( net->pins.size() )
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
|
|
|
// give ownership to pcb->network
|
|
|
|
pcb->network->nets.push_back( net );
|
|
|
|
nets[n] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-29 22:09:09 +00:00
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-08-09 19:05:04 +00:00
|
|
|
//-----< output vias used in netclasses >-----------------------------------
|
2008-02-14 01:07:52 +00:00
|
|
|
{
|
2020-05-31 21:42:04 +00:00
|
|
|
NETCLASSES& nclasses = aBoard->GetDesignSettings().GetNetClasses();
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-09-01 17:59:28 +00:00
|
|
|
// Assume the netclass vias are all the same kind of thru, blind, or buried vias.
|
|
|
|
// This is in lieu of either having each netclass via have its own layer pair in
|
|
|
|
// the netclass dialog, or such control in the specctra export dialog.
|
|
|
|
|
|
|
|
|
|
|
|
// if( aBoard->GetDesignSettings().m_CurrentViaType == VIA_THROUGH )
|
|
|
|
{
|
|
|
|
m_top_via_layer = 0; // first specctra cu layer is number zero.
|
|
|
|
m_bot_via_layer = aBoard->GetCopperLayerCount()-1;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// again, should be in the BOARD:
|
|
|
|
topLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_TOP ];
|
|
|
|
botLayer = kicadLayer2pcb[ GetScreen()->m_Route_Layer_BOTTOM ];
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
// Add the via from the Default netclass first. The via container
|
|
|
|
// in pcb->library preserves the sequence of addition.
|
2008-02-14 01:07:52 +00:00
|
|
|
|
2014-05-20 09:29:37 +00:00
|
|
|
NETCLASSPTR netclass = nclasses.GetDefault();
|
2009-11-02 05:20:58 +00:00
|
|
|
|
|
|
|
PADSTACK* via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
|
2013-09-01 17:59:28 +00:00
|
|
|
m_top_via_layer, m_bot_via_layer );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
// we AppendVia() this first one, there is no way it can be a duplicate,
|
|
|
|
// the pcb->library via container is empty at this point. After this,
|
|
|
|
// we'll have to use LookupVia().
|
|
|
|
wxASSERT( pcb->library->vias.size() == 0 );
|
|
|
|
pcb->library->AppendVia( via );
|
|
|
|
|
2013-08-09 19:05:04 +00:00
|
|
|
#if 0
|
2013-09-01 17:59:28 +00:00
|
|
|
// I've seen no way to make stock vias useable by freerouter. Also the
|
|
|
|
// zero based diameter was leading to duplicates in the LookupVia() function.
|
2013-08-09 19:05:04 +00:00
|
|
|
// User should use netclass based vias when going to freerouter.
|
|
|
|
|
2013-09-01 17:59:28 +00:00
|
|
|
// Output the stock vias, but preserve uniqueness in the via container by
|
2009-11-02 05:20:58 +00:00
|
|
|
// using LookupVia().
|
2013-04-30 15:25:41 +00:00
|
|
|
for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i )
|
2008-01-29 22:09:09 +00:00
|
|
|
{
|
2013-04-30 15:25:41 +00:00
|
|
|
int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter;
|
|
|
|
int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
via = makeVia( viaSize, viaDrill,
|
2013-09-01 17:59:28 +00:00
|
|
|
m_top_via_layer, m_bot_via_layer );
|
2008-01-29 22:09:09 +00:00
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
// maybe add 'via' to the library, but only if unique.
|
|
|
|
PADSTACK* registered = pcb->library->LookupVia( via );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
if( registered != via )
|
|
|
|
delete via;
|
|
|
|
}
|
2013-08-09 19:05:04 +00:00
|
|
|
#endif
|
2009-11-02 05:20:58 +00:00
|
|
|
|
|
|
|
// set the "spare via" index at the start of the
|
|
|
|
// pcb->library->spareViaIndex = pcb->library->vias.size();
|
|
|
|
|
|
|
|
// output the non-Default netclass vias
|
2013-04-30 15:25:41 +00:00
|
|
|
for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
|
2009-11-02 05:20:58 +00:00
|
|
|
{
|
|
|
|
netclass = nc->second;
|
|
|
|
|
|
|
|
via = makeVia( netclass->GetViaDiameter(), netclass->GetViaDrill(),
|
2013-09-01 17:59:28 +00:00
|
|
|
m_top_via_layer, m_bot_via_layer );
|
2009-11-02 05:20:58 +00:00
|
|
|
|
|
|
|
// maybe add 'via' to the library, but only if unique.
|
|
|
|
PADSTACK* registered = pcb->library->LookupVia( via );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
if( registered != via )
|
|
|
|
delete via;
|
2008-01-29 22:09:09 +00:00
|
|
|
}
|
|
|
|
}
|
2008-01-30 19:16:46 +00:00
|
|
|
|
2008-02-14 01:07:52 +00:00
|
|
|
|
2013-04-30 15:25:41 +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.
|
2011-10-01 19:24:27 +00:00
|
|
|
static const KICAD_T scanTRACKs[] = { PCB_TRACE_T, 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;
|
2013-03-31 13:27:46 +00:00
|
|
|
LAYER_NUM old_layer = UNDEFINED_LAYER;
|
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
|
|
|
|
2014-02-25 10:40:34 +00:00
|
|
|
int netcode = track->GetNetCode();
|
2008-02-29 06:49:34 +00:00
|
|
|
|
|
|
|
if( netcode == 0 )
|
2008-01-31 01:30:52 +00:00
|
|
|
continue;
|
|
|
|
|
2015-11-11 18:47:51 +00:00
|
|
|
if( old_netcode != netcode ||
|
|
|
|
old_width != track->GetWidth() ||
|
|
|
|
old_layer != track->GetLayer() ||
|
|
|
|
(path && path->points.back() != mapPt(track->GetStart()) )
|
2008-02-07 20:23:58 +00:00
|
|
|
)
|
2008-01-31 01:30:52 +00:00
|
|
|
{
|
2013-01-13 00:04:00 +00:00
|
|
|
old_width = track->GetWidth();
|
2008-01-31 06:46:31 +00:00
|
|
|
old_layer = track->GetLayer();
|
2008-01-31 01:30:52 +00:00
|
|
|
|
2008-02-29 06:49:34 +00:00
|
|
|
if( old_netcode != netcode )
|
2008-01-31 01:30:52 +00:00
|
|
|
{
|
2008-02-29 06:49:34 +00:00
|
|
|
old_netcode = netcode;
|
2009-05-24 18:28:36 +00:00
|
|
|
NETINFO_ITEM* net = aBoard->FindNet( netcode );
|
|
|
|
wxASSERT( net );
|
2011-02-02 15:31:48 +00:00
|
|
|
netname = TO_UTF8( net->GetNetname() );
|
2008-01-31 01:30:52 +00:00
|
|
|
}
|
2008-01-31 06:46:31 +00:00
|
|
|
|
|
|
|
WIRE* wire = new WIRE( wiring );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-01-31 06:46:31 +00:00
|
|
|
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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
wire->wire_type = T_protect; // @todo, this should be configurable
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-03-31 13:27:46 +00:00
|
|
|
LAYER_NUM kiLayer = track->GetLayer();
|
2013-05-05 10:11:30 +00:00
|
|
|
int pcbLayer = kicadLayer2pcb[kiLayer];
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-01-31 06:46:31 +00:00
|
|
|
path = new PATH( wire );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-01-31 06:46:31 +00:00
|
|
|
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 );
|
|
|
|
|
2013-01-13 00:04:00 +00:00
|
|
|
path->AppendPoint( mapPt( track->GetStart() ) );
|
2008-01-31 01:30:52 +00:00
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2015-11-11 18:47:51 +00:00
|
|
|
if( path ) // Should not occur
|
|
|
|
path->AppendPoint( mapPt( track->GetEnd() ) );
|
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
|
|
|
{
|
2013-09-01 17:59:28 +00:00
|
|
|
// Export all vias, once per unique size and drill diameter combo.
|
2011-10-01 19:24:27 +00:00
|
|
|
static const KICAD_T scanVIAs[] = { PCB_VIA_T, 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
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( int i = 0; i<items.GetCount(); ++i )
|
2008-02-01 01:09:39 +00:00
|
|
|
{
|
2014-04-25 06:00:04 +00:00
|
|
|
::VIA* via = (::VIA*) items[i];
|
2011-10-01 19:24:27 +00:00
|
|
|
wxASSERT( via->Type() == PCB_VIA_T );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2014-02-25 10:40:34 +00:00
|
|
|
int netcode = via->GetNetCode();
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-21 06:04:32 +00:00
|
|
|
if( netcode == 0 )
|
|
|
|
continue;
|
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
PADSTACK* padstack = makeVia( via );
|
|
|
|
PADSTACK* registered = pcb->library->LookupVia( padstack );
|
2008-10-30 18:54:16 +00:00
|
|
|
|
|
|
|
// if the one looked up is not our padstack, then delete our padstack
|
|
|
|
// since it was a duplicate of one already registered.
|
2008-02-01 01:09:39 +00:00
|
|
|
if( padstack != registered )
|
|
|
|
{
|
|
|
|
delete padstack;
|
|
|
|
}
|
|
|
|
|
|
|
|
WIRE_VIA* dsnVia = new WIRE_VIA( pcb->wiring );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2008-02-01 01:09:39 +00:00
|
|
|
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
|
|
|
|
2009-05-24 18:28:36 +00:00
|
|
|
NETINFO_ITEM* net = aBoard->FindNet( netcode );
|
|
|
|
wxASSERT( net );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2011-02-02 15:31:48 +00:00
|
|
|
dsnVia->net_id = TO_UTF8( net->GetNetname() );
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-21 06:04:32 +00:00
|
|
|
dsnVia->via_type = T_protect; // @todo, this should be configurable
|
2008-02-01 01:09:39 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
#endif // do existing wires and vias
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2008-02-01 01:09:39 +00:00
|
|
|
//-----<via_descriptor>-------------------------------------------------
|
|
|
|
{
|
2009-11-02 05:20:58 +00:00
|
|
|
// The pcb->library will output <padstack_descriptors> which is a combined
|
|
|
|
// list of part padstacks and via padstacks. specctra dsn uses the
|
|
|
|
// <via_descriptors> to say which of those padstacks are vias.
|
|
|
|
|
|
|
|
// Output the vias in the padstack list here, by name only. This must
|
2008-02-01 01:09:39 +00:00
|
|
|
// be done after exporting existing vias as WIRE_VIAs.
|
2013-04-30 15:25:41 +00:00
|
|
|
VIA* vias = pcb->structure->via;
|
2008-02-01 01:09:39 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( unsigned viaNdx = 0; viaNdx < pcb->library->vias.size(); ++viaNdx )
|
2008-02-01 01:09:39 +00:00
|
|
|
{
|
2009-11-02 05:20:58 +00:00
|
|
|
vias->AppendVia( pcb->library->vias[viaNdx].padstack_id.c_str() );
|
2008-02-01 01:09:39 +00:00
|
|
|
}
|
2008-01-30 19:16:46 +00:00
|
|
|
}
|
2008-02-01 01:09:39 +00:00
|
|
|
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
//-----<output NETCLASSs>----------------------------------------------------
|
2020-05-31 21:42:04 +00:00
|
|
|
NETCLASSES& nclasses = aBoard->GetDesignSettings().GetNetClasses();
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2009-11-02 05:20:58 +00:00
|
|
|
exportNETCLASS( nclasses.GetDefault(), aBoard );
|
2009-09-10 15:22:26 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( NETCLASSES::iterator nc = nclasses.begin(); nc != nclasses.end(); ++nc )
|
2008-02-29 06:49:34 +00:00
|
|
|
{
|
2014-05-20 09:29:37 +00:00
|
|
|
NETCLASSPTR netclass = nc->second;
|
2009-11-02 05:20:58 +00:00
|
|
|
exportNETCLASS( netclass, aBoard );
|
2009-09-10 15:22:26 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-29 06:49:34 +00:00
|
|
|
|
|
|
|
|
2017-09-23 09:20:10 +00:00
|
|
|
void SPECCTRA_DB::exportNETCLASS( const NETCLASSPTR& aNetClass, BOARD* aBoard )
|
2009-09-10 15:22:26 +00:00
|
|
|
{
|
2013-09-01 17:59:28 +00:00
|
|
|
/* From page 11 of specctra spec:
|
|
|
|
*
|
|
|
|
* Routing and Placement Rule Hierarchies
|
|
|
|
*
|
|
|
|
* Routing and placement rules can be defined at multiple levels of design
|
|
|
|
* specification. When a routing or placement rule is defined for an object at
|
|
|
|
* multiple levels, a predefined routing or placement precedence order
|
|
|
|
* automatically determines which rule to apply to the object. The routing rule
|
|
|
|
* precedence order is
|
|
|
|
*
|
|
|
|
* pcb < layer < class < class layer < group_set < group_set layer < net <
|
|
|
|
* net layer < group < group layer < fromto < fromto layer < class_class <
|
|
|
|
* class_class layer < padstack < region < class region < net region <
|
|
|
|
* class_class region
|
|
|
|
*
|
|
|
|
* A pcb rule (global rule for the PCB design) has the lowest precedence in the
|
|
|
|
* hierarchy. A class-to-class region rule has the highest precedence. Rules
|
|
|
|
* set at one level of the hierarchy override conflicting rules set at lower
|
|
|
|
* levels. The placement rule precedence order is
|
|
|
|
*
|
|
|
|
* pcb < image_set < image < component < super cluster < room <
|
|
|
|
* room_image_set < family_family < image_image
|
|
|
|
*
|
|
|
|
* A pcb rule (global rule for the PCB design) has the lowest precedence in the
|
|
|
|
* hierarchy. An image-to-image rule has the highest precedence. Rules set at
|
|
|
|
* one level of the hierarchy override conflicting rules set at lower levels.
|
|
|
|
*/
|
2009-11-02 05:20:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
char text[256];
|
2008-02-29 06:49:34 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
CLASS* clazz = new CLASS( pcb->network );
|
2013-04-30 15:25:41 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
pcb->network->classes.push_back( clazz );
|
2008-02-29 06:49:34 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
// freerouter creates a class named 'default' anyway, and if we
|
|
|
|
// try and use that, we end up with two 'default' via rules so use
|
|
|
|
// something else as the name of our default class.
|
2011-02-02 15:31:48 +00:00
|
|
|
clazz->class_id = TO_UTF8( aNetClass->GetName() );
|
2008-02-29 06:49:34 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
for( NETCLASS::iterator net = aNetClass->begin(); net != aNetClass->end(); ++net )
|
2011-02-02 15:31:48 +00:00
|
|
|
clazz->net_ids.push_back( TO_UTF8( *net ) );
|
2008-02-14 15:34:40 +00:00
|
|
|
|
2009-09-10 15:22:26 +00:00
|
|
|
clazz->rules = new RULE( clazz, T_rule );
|
|
|
|
|
|
|
|
// output the track width.
|
2013-04-30 15:25:41 +00:00
|
|
|
int trackWidth = aNetClass->GetTrackWidth();
|
2009-09-10 15:22:26 +00:00
|
|
|
sprintf( text, "(width %.6g)", scale( trackWidth ) );
|
|
|
|
clazz->rules->rules.push_back( text );
|
|
|
|
|
|
|
|
// output the clearance.
|
|
|
|
int clearance = aNetClass->GetClearance();
|
|
|
|
sprintf( text, "(clearance %.6g)", scale( clearance ) + safetyMargin );
|
|
|
|
clazz->rules->rules.push_back( text );
|
|
|
|
|
|
|
|
if( aNetClass->GetName() == NETCLASS::Default )
|
|
|
|
{
|
|
|
|
clazz->class_id = "kicad_default";
|
|
|
|
}
|
2009-11-02 05:20:58 +00:00
|
|
|
|
|
|
|
// the easiest way to get the via name is to create a via (which generates
|
|
|
|
// the name internal to the PADSTACK), and then grab the name and then
|
|
|
|
// delete the via. There are not that many netclasses so
|
|
|
|
// this should never become a performance issue.
|
|
|
|
|
|
|
|
PADSTACK* via = makeVia( aNetClass->GetViaDiameter(), aNetClass->GetViaDrill(),
|
2013-09-01 17:59:28 +00:00
|
|
|
m_top_via_layer, m_bot_via_layer );
|
2009-11-02 05:20:58 +00:00
|
|
|
|
|
|
|
snprintf( text, sizeof(text), "(use_via %s)", via->GetPadstackId().c_str() );
|
|
|
|
clazz->circuit.push_back( text );
|
|
|
|
|
|
|
|
delete via;
|
2008-02-14 15:34:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-29 06:49:34 +00:00
|
|
|
void SPECCTRA_DB::FlipMODULEs( BOARD* aBoard )
|
2008-02-14 15:34:40 +00:00
|
|
|
{
|
2020-05-19 08:20:12 +00:00
|
|
|
// DSN Images (=KiCad MODULES and pads) must be presented from the
|
|
|
|
// top view.
|
|
|
|
// Note: to export footprints, the footprints must be flipped around the X axis,
|
|
|
|
// otherwise the rotation angle is not good
|
2019-05-31 00:15:57 +00:00
|
|
|
for( auto module : aBoard->Modules() )
|
2008-02-14 15:34:40 +00:00
|
|
|
{
|
2013-03-13 18:53:58 +00:00
|
|
|
module->SetFlag( 0 );
|
2014-06-24 16:17:18 +00:00
|
|
|
if( module->GetLayer() == B_Cu )
|
2008-02-14 15:34:40 +00:00
|
|
|
{
|
2020-05-19 08:20:12 +00:00
|
|
|
module->Flip( module->GetPosition(), false );
|
2013-03-13 18:53:58 +00:00
|
|
|
module->SetFlag( 1 );
|
2008-02-14 15:34:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
modulesAreFlipped = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SPECCTRA_DB::RevertMODULEs( BOARD* aBoard )
|
|
|
|
{
|
|
|
|
if( !modulesAreFlipped )
|
|
|
|
return;
|
2008-02-07 20:23:58 +00:00
|
|
|
|
2013-04-30 15:25:41 +00:00
|
|
|
// DSN Images (=KiCad MODULES and pads) must be presented from the
|
|
|
|
// top view. Restore those that were flipped.
|
2020-05-19 08:20:12 +00:00
|
|
|
// Note: to export footprints, the footprints were flipped around the X axis,
|
2019-05-31 00:15:57 +00:00
|
|
|
for( auto module : aBoard->Modules() )
|
2008-01-25 22:03:36 +00:00
|
|
|
{
|
2013-03-13 18:53:58 +00:00
|
|
|
if( module->GetFlag() )
|
2008-01-25 22:03:36 +00:00
|
|
|
{
|
2020-05-19 08:20:12 +00:00
|
|
|
module->Flip( module->GetPosition(), false );
|
2013-03-13 18:53:58 +00:00
|
|
|
module->SetFlag( 0 );
|
2008-01-25 22:03:36 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-14 15:34:40 +00:00
|
|
|
|
|
|
|
modulesAreFlipped = false;
|
2008-01-22 20:48:02 +00:00
|
|
|
}
|
Modular KiCad Blueprint Milestone B), major portions:
*) When kicad.exe closes a project, close any open KIFACEs so that they cannot
get disassociated from their true PROJECT.
*) Allow loading eeschema library editor from kicad.exe
*) Allow loading pcbnew library editor from kicad.exe
*) Rename LIB_COMPONENT to LIB_PART.
*) Add class PART_LIBS, and PART_LIB.
*) Make PART_LIBS non-global, i.e. PROJECT specific.
*) Implement "data on demand" for PART_LIBS
*) Implement "data on demand" for schematic SEARCH_STACK.
*) Use RSTRINGs to retain eeschema editor's notion of last library and part being edited.
*) Get rid of library search on every SCH_COMPONENT::Draw() call, instead use
a weak pointer.
*) Remove all chdir() calls so projects don't need to be CWD.
*) Romove APPEND support from OpenProjectFiles().
*) Make OpenProjectFiles() robust, even for creating new projects.
*) Load EESCHEMA colors in the KIWAY::OnKiwayStart() rather in window open,
and save them in the .eeschema config file, not in the project file.
*) Fix bug with wxDir() while accessing protected dirs in kicad.exe
*) Consolidate template copying into PROJECT class, not in kicad.exe source.
*) Generally untangle eeschema, making its libraries not global but rather
held in the PROJECT.
2014-08-13 20:28:54 +00:00
|
|
|
|
2008-01-21 21:24:39 +00:00
|
|
|
} // namespace DSN
|