Pcbnew: add footprint keepouts to Specctra DSN exporter.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/7684
This commit is contained in:
parent
df2154a87a
commit
d4231d8e9f
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2007-2015 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2015-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2015-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -64,7 +64,8 @@ using namespace DSN;
|
|||
// 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).
|
||||
// - 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
|
||||
|
||||
|
@ -95,7 +96,7 @@ bool PCB_EDIT_FRAME::ExportSpecctraFile( const wxString& aFullFilename )
|
|||
// DSN Images (=KiCad FOOTPRINTs and PADs) must be presented from the top view. So we
|
||||
// temporarily flip any footprints which are on the back side of the board to the front,
|
||||
// and record this in the FOOTPRINT's flag field.
|
||||
db.FlipFOOTPRINTs( GetBoard());
|
||||
db.FlipFOOTPRINTs( GetBoard() );
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -115,7 +116,7 @@ bool PCB_EDIT_FRAME::ExportSpecctraFile( const wxString& aFullFilename )
|
|||
}
|
||||
|
||||
// done assuredly, even if an exception was thrown and caught.
|
||||
db.RevertFOOTPRINTs( GetBoard());
|
||||
db.RevertFOOTPRINTs( GetBoard() );
|
||||
|
||||
// The two calls below to FOOTPRINT::Flip(), both set the
|
||||
// modified flag, yet their actions cancel each other out, so it should
|
||||
|
@ -147,8 +148,7 @@ const KICAD_T SPECCTRA_DB::scanPADs[] = { PCB_PAD_T, EOT };
|
|||
|
||||
|
||||
/**
|
||||
* Function scale
|
||||
* converts a distance from PCBNEW internal units to the reported specctra dsn units
|
||||
* Convert a distance from Pcbnew internal units to the reported Specctra DSN units
|
||||
* in floating point format.
|
||||
*/
|
||||
static inline double scale( int kicadDist )
|
||||
|
@ -158,7 +158,7 @@ static inline double scale( int kicadDist )
|
|||
}
|
||||
|
||||
|
||||
// / Convert integer internal units to float um
|
||||
///< Convert integer internal units to float um
|
||||
static inline double IU2um( int kicadDist )
|
||||
{
|
||||
return kicadDist * (1000.0 / IU_PER_MM);
|
||||
|
@ -178,10 +178,10 @@ static inline double mapY( int y )
|
|||
|
||||
|
||||
/**
|
||||
* Function mapPt
|
||||
* converts a KiCad point into a DSN file point. Kicad's BOARD coordinates
|
||||
* are in nanometers (called Internal Units or IU)and we are exporting in units
|
||||
* of mils, so we have to scale them.
|
||||
* Convert a KiCad point into a DSN file point.
|
||||
*
|
||||
* Kicad's #BOARD coordinates are in nanometers (called Internal Units or IU) and we are
|
||||
* exporting in units of mils, so we have to scale them.
|
||||
*/
|
||||
static POINT mapPt( const wxPoint& pt )
|
||||
{
|
||||
|
@ -195,13 +195,11 @@ static POINT mapPt( const wxPoint& pt )
|
|||
|
||||
|
||||
/**
|
||||
* Function isRoundKeepout
|
||||
* decides if the pad is a copper-less through hole which needs to be made into
|
||||
* a round keepout.
|
||||
* Decide if the pad is a copper-less through hole which needs to be made into a round keepout.
|
||||
*/
|
||||
static bool isRoundKeepout( PAD* aPad )
|
||||
{
|
||||
if( aPad->GetShape()==PAD_SHAPE_CIRCLE )
|
||||
if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
|
||||
{
|
||||
if( aPad->GetDrillSize().x >= aPad->GetSize().x )
|
||||
return true;
|
||||
|
@ -215,8 +213,7 @@ static bool isRoundKeepout( PAD* aPad )
|
|||
|
||||
|
||||
/**
|
||||
* Function makePath
|
||||
* creates a PATH element with a single straight line, a pair of vertices.
|
||||
* Create 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 )
|
||||
{
|
||||
|
@ -568,7 +565,8 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, PAD* aPad )
|
|||
|
||||
for( unsigned idx = 0; idx < polygonal_shape.size(); idx++ )
|
||||
{
|
||||
POINT corner( scale( polygonal_shape[idx].x ), scale( -polygonal_shape[idx].y ) );
|
||||
POINT corner( scale( polygonal_shape[idx].x ),
|
||||
scale( -polygonal_shape[idx].y ) );
|
||||
corner += dsnOffset;
|
||||
polygon->AppendPoint( corner );
|
||||
}
|
||||
|
@ -578,9 +576,9 @@ PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, PAD* aPad )
|
|||
MD5_HASH hash = pad_shape.GetHash();
|
||||
EDA_RECT rect = aPad->GetBoundingBox();
|
||||
snprintf( name, sizeof(name), "Cust%sPad_%.6gx%.6g_%.6gx_%.6g_%d_um_%s",
|
||||
uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
|
||||
IU2um( rect.GetWidth() ), IU2um( rect.GetHeight() ),
|
||||
(int)polygonal_shape.size(), hash.Format( true ).c_str() );
|
||||
uniqifier.c_str(), IU2um( aPad->GetSize().x ), IU2um( aPad->GetSize().y ),
|
||||
IU2um( rect.GetWidth() ), IU2um( rect.GetHeight() ),
|
||||
(int)polygonal_shape.size(), hash.Format( true ).c_str() );
|
||||
name[ sizeof(name)-1 ] = 0;
|
||||
|
||||
padstack->SetPadstackId( name );
|
||||
|
@ -606,7 +604,7 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
|
|||
// get all the FOOTPRINT's pads.
|
||||
fpItems.Collect( aFootprint, scanPADs );
|
||||
|
||||
IMAGE* image = new IMAGE(0);
|
||||
IMAGE* image = new IMAGE( 0 );
|
||||
|
||||
image->image_id = aFootprint->GetFPID().Format().c_str();
|
||||
|
||||
|
@ -668,7 +666,7 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
|
|||
padName = pad->GetName();
|
||||
pin->pin_id = TO_UTF8( padName );
|
||||
|
||||
if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() )
|
||||
if( padName != wxEmptyString && pinmap.find( padName ) == pinmap.end() )
|
||||
{
|
||||
pinmap[ padName ] = 0;
|
||||
}
|
||||
|
@ -699,7 +697,6 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
|
|||
}
|
||||
}
|
||||
|
||||
#if 1 // enable image (outline) scopes.
|
||||
static const KICAD_T scanEDGEs[] = { PCB_FP_SHAPE_T, EOT };
|
||||
|
||||
// get all the FOOTPRINT's FP_SHAPEs and convert those to DSN outlines.
|
||||
|
@ -775,14 +772,130 @@ IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, FOOTPRINT* aFootprint )
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
for( FP_ZONE* zone : aFootprint->Zones() )
|
||||
{
|
||||
if( !zone->GetIsRuleArea() )
|
||||
continue;
|
||||
|
||||
// IMAGE object coordinates are relative to the IMAGE not absolute board coordinates.
|
||||
ZONE untransformedZone( *zone );
|
||||
|
||||
double angle = -aFootprint->GetOrientation();
|
||||
NORMALIZE_ANGLE_POS( angle );
|
||||
untransformedZone.Rotate( aFootprint->GetPosition(), angle );
|
||||
|
||||
// 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( zone->GetDoNotAllowVias() && zone->GetDoNotAllowTracks() )
|
||||
keepout_type = T_keepout;
|
||||
else if( zone->GetDoNotAllowVias() )
|
||||
keepout_type = T_via_keepout;
|
||||
else if( zone->GetDoNotAllowTracks() )
|
||||
keepout_type = T_wire_keepout;
|
||||
else
|
||||
keepout_type = T_keepout;
|
||||
|
||||
// Now, build keepout polygon on each copper layer where the zone
|
||||
// keepout is living (keepout zones can live on many copper layers)
|
||||
const int copperCount = aBoard->GetCopperLayerCount();
|
||||
|
||||
for( int layer = 0; layer < copperCount; layer++ )
|
||||
{
|
||||
if( layer == copperCount-1 )
|
||||
layer = B_Cu;
|
||||
|
||||
if( !zone->IsOnLayer( PCB_LAYER_ID( layer ) ) )
|
||||
continue;
|
||||
|
||||
KEEPOUT* keepout = new KEEPOUT( m_pcb->structure, keepout_type );
|
||||
image->keepouts.push_back( keepout );
|
||||
|
||||
PATH* mainPolygon = new PATH( keepout, T_polygon );
|
||||
keepout->SetShape( mainPolygon );
|
||||
|
||||
mainPolygon->layer_id = m_layerIds[ m_kicadLayer2pcb[ layer ] ];
|
||||
|
||||
// Handle the main outlines
|
||||
SHAPE_POLY_SET::ITERATOR iterator;
|
||||
bool is_first_point = true;
|
||||
wxPoint startpoint;
|
||||
|
||||
for( iterator = untransformedZone.IterateWithHoles(); iterator; iterator++ )
|
||||
{
|
||||
wxPoint point( iterator->x, iterator->y );
|
||||
|
||||
point -= aFootprint->GetPosition();
|
||||
|
||||
if( is_first_point )
|
||||
{
|
||||
startpoint = point;
|
||||
is_first_point = false;
|
||||
}
|
||||
|
||||
mainPolygon->AppendPoint( mapPt( point ) );
|
||||
|
||||
// this was the end of the main polygon
|
||||
if( iterator.IsEndContour() )
|
||||
{
|
||||
mainPolygon->AppendPoint( mapPt( startpoint ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WINDOW* window = nullptr;
|
||||
PATH* cutout = nullptr;
|
||||
bool isStartContour = true;
|
||||
|
||||
// handle the cutouts
|
||||
for( iterator++; iterator; iterator++ )
|
||||
{
|
||||
if( isStartContour )
|
||||
{
|
||||
is_first_point = true;
|
||||
window = new WINDOW( keepout );
|
||||
keepout->AddWindow( window );
|
||||
|
||||
cutout = new PATH( window, T_polygon );
|
||||
|
||||
window->SetShape( cutout );
|
||||
|
||||
cutout->layer_id = m_layerIds[ m_kicadLayer2pcb[ zone->GetLayer() ] ];
|
||||
}
|
||||
|
||||
isStartContour = iterator.IsEndContour();
|
||||
|
||||
wxASSERT( window );
|
||||
wxASSERT( cutout );
|
||||
|
||||
wxPoint point( iterator->x, iterator->y );
|
||||
|
||||
point -= aFootprint->GetPosition();
|
||||
|
||||
if( is_first_point )
|
||||
{
|
||||
startpoint = point;
|
||||
is_first_point = false;
|
||||
}
|
||||
|
||||
cutout->AppendPoint( mapPt( point ) );
|
||||
|
||||
// Close the polygon
|
||||
if( iterator.IsEndContour() )
|
||||
cutout->AppendPoint( mapPt( startpoint ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
|
||||
int aTopLayer, int aBotLayer )
|
||||
int aTopLayer, int aBotLayer )
|
||||
{
|
||||
char name[48];
|
||||
PADSTACK* padstack = new PADSTACK();
|
||||
|
@ -802,11 +915,10 @@ PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
|
|||
circle->SetLayerId( m_layerIds[layer].c_str() );
|
||||
}
|
||||
|
||||
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_um",
|
||||
snprintf( name, sizeof( name ), "Via[%d-%d]_%.6g:%.6g_um",
|
||||
aTopLayer, aBotLayer, dsnDiameter,
|
||||
// encode the drill value into the name for later import
|
||||
IU2um( aDrillDiameter )
|
||||
);
|
||||
IU2um( aDrillDiameter ) );
|
||||
|
||||
name[ sizeof(name) - 1 ] = 0;
|
||||
padstack->SetPadstackId( name );
|
||||
|
@ -956,12 +1068,9 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
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.
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -988,7 +1097,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
m_pcb->unit->units = T_um;
|
||||
m_pcb->resolution->units = T_um;
|
||||
m_pcb->resolution->value = 10; // tenths of a um
|
||||
// pcb->resolution->value = 1000; // "thousandths of a um" (i.e. "nm")
|
||||
}
|
||||
|
||||
//-----<boundary_descriptor>------------------------------------------
|
||||
|
@ -1002,7 +1110,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
fillBOUNDARY( aBoard, boundary );
|
||||
}
|
||||
|
||||
|
||||
//-----<rules>--------------------------------------------------------
|
||||
{
|
||||
char rule[80];
|
||||
|
@ -1038,29 +1145,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
|
||||
rules.push_back( rule );
|
||||
|
||||
/* see: http://www.freerouting.net/usren/viewtopic.php?f=5&t=339#p474
|
||||
sprintf( rule, "(clearance %.6g (type pad_to_turn_gap))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
|
||||
sprintf( rule, "(clearance %.6g (type smd_to_turn_gap))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
|
||||
sprintf( rule, "(clearance %.6g (type via_via))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
|
||||
sprintf( rule, "(clearance %.6g (type via_smd))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
|
||||
sprintf( rule, "(clearance %.6g (type via_pin))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
|
||||
sprintf( rule, "(clearance %.6g (type pin_pin))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
|
||||
sprintf( rule, "(clearance %.6g (type smd_pin))", clearance + safetyMargin );
|
||||
rules.push_back( rule );
|
||||
*/
|
||||
|
||||
// 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.
|
||||
|
@ -1070,9 +1154,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
rules.push_back( rule );
|
||||
}
|
||||
|
||||
|
||||
//-----<zones (not keepout areas) become planes>--------------------------------
|
||||
// Note: only zones are output here, keepout areas be be created later
|
||||
// Note: only zones are output here, keepout areas are created later.
|
||||
{
|
||||
int netlessZones = 0;
|
||||
|
||||
|
@ -1183,7 +1266,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
is_first_point = false;
|
||||
}
|
||||
|
||||
cutout->AppendPoint( mapPt(point) );
|
||||
cutout->AppendPoint( mapPt( point ) );
|
||||
|
||||
// Close the polygon
|
||||
if( iterator.IsEndContour() )
|
||||
|
@ -1225,7 +1308,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
|
||||
for( int layer = 0; layer < copperCount; layer++ )
|
||||
{
|
||||
if( layer == copperCount-1)
|
||||
if( layer == copperCount - 1 )
|
||||
layer = B_Cu;
|
||||
|
||||
if( !item->IsOnLayer( PCB_LAYER_ID( layer ) ) )
|
||||
|
@ -1254,7 +1337,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
is_first_point = false;
|
||||
}
|
||||
|
||||
mainPolygon->AppendPoint( mapPt(point) );
|
||||
mainPolygon->AppendPoint( mapPt( point ) );
|
||||
|
||||
// this was the end of the main polygon
|
||||
if( iterator.IsEndContour() )
|
||||
|
@ -1374,7 +1457,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
IMAGE* registered = m_pcb->library->LookupIMAGE( image );
|
||||
|
||||
if( registered != image )
|
||||
|
@ -1432,7 +1514,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//-----< output vias used in netclasses >-----------------------------------
|
||||
{
|
||||
NETCLASSES& nclasses = aBoard->GetDesignSettings().GetNetClasses();
|
||||
|
@ -1442,19 +1523,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
// 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 ];
|
||||
}
|
||||
*/
|
||||
m_top_via_layer = 0; // first specctra cu layer is number zero.
|
||||
m_bot_via_layer = aBoard->GetCopperLayerCount()-1;
|
||||
|
||||
// Add the via from the Default netclass first. The via container
|
||||
// in pcb->library preserves the sequence of addition.
|
||||
|
@ -1470,29 +1540,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
wxASSERT( m_pcb->library->vias.size() == 0 );
|
||||
m_pcb->library->AppendVia( via );
|
||||
|
||||
#if 0
|
||||
// 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.
|
||||
// User should use netclass based vias when going to freerouter.
|
||||
|
||||
// Output the stock vias, but preserve uniqueness in the via container by
|
||||
// using LookupVia().
|
||||
for( unsigned i = 0; i < aBoard->m_ViasDimensionsList.size(); ++i )
|
||||
{
|
||||
int viaSize = aBoard->m_ViasDimensionsList[i].m_Diameter;
|
||||
int viaDrill = aBoard->m_ViasDimensionsList[i].m_Drill;
|
||||
|
||||
via = makeVia( viaSize, viaDrill,
|
||||
m_top_via_layer, m_bot_via_layer );
|
||||
|
||||
// maybe add 'via' to the library, but only if unique.
|
||||
PADSTACK* registered = pcb->library->LookupVia( via );
|
||||
|
||||
if( registered != via )
|
||||
delete via;
|
||||
}
|
||||
#endif
|
||||
|
||||
// set the "spare via" index at the start of the
|
||||
// pcb->library->spareViaIndex = pcb->library->vias.size();
|
||||
|
||||
|
@ -1512,9 +1559,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#if 1 // do existing wires and vias
|
||||
|
||||
//-----<create the wires from tracks>-----------------------------------
|
||||
{
|
||||
// export all of them for now, later we'll decide what controls we need
|
||||
|
@ -1540,11 +1584,9 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
if( netcode == 0 )
|
||||
continue;
|
||||
|
||||
if( old_netcode != netcode ||
|
||||
old_width != track->GetWidth() ||
|
||||
old_layer != track->GetLayer() ||
|
||||
(path && path->points.back() != mapPt(track->GetStart()) )
|
||||
)
|
||||
if( old_netcode != netcode || old_width != track->GetWidth() ||
|
||||
old_layer != track->GetLayer() ||
|
||||
( path && path->points.back() != mapPt(track->GetStart() ) ) )
|
||||
{
|
||||
old_width = track->GetWidth();
|
||||
old_layer = track->GetLayer();
|
||||
|
@ -1582,7 +1624,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//-----<export the existing real BOARD instantiated vias>-----------------
|
||||
{
|
||||
// Export all vias, once per unique size and drill diameter combo.
|
||||
|
@ -1626,8 +1667,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
}
|
||||
}
|
||||
|
||||
#endif // do existing wires and vias
|
||||
|
||||
//-----<via_descriptor>-------------------------------------------------
|
||||
{
|
||||
// The pcb->library will output <padstack_descriptors> which is a combined
|
||||
|
@ -1644,7 +1683,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//-----<output NETCLASSs>----------------------------------------------------
|
||||
NETCLASSES& nclasses = aBoard->GetDesignSettings().GetNetClasses();
|
||||
|
||||
|
@ -1743,6 +1781,7 @@ void SPECCTRA_DB::FlipFOOTPRINTs( BOARD* aBoard )
|
|||
for( FOOTPRINT* footprint : aBoard->Footprints() )
|
||||
{
|
||||
footprint->SetFlag( 0 );
|
||||
|
||||
if( footprint->GetLayer() == B_Cu )
|
||||
{
|
||||
footprint->Flip( footprint->GetPosition(), false );
|
||||
|
|
Loading…
Reference in New Issue