Allow a user to remap layers in Eagle import

ADDED Allow for user mapping of layers in Eagle import
ADDED Support required and optional layers in the layer mapping dialog
ADDED Add base class for plugins supporting remappable layers
This commit is contained in:
Jan Mrázek 2020-10-09 18:58:21 +02:00
parent f7333ad64a
commit fc8bf6f0fe
No known key found for this signature in database
GPG Key ID: A3E71126F180EB6F
10 changed files with 475 additions and 191 deletions

View File

@ -24,6 +24,30 @@
#include <wx/msgdlg.h>
wxString DIALOG_IMPORTED_LAYERS::WrapRequired( const wxString& aLayerName )
{
return aLayerName + " *";
}
wxString DIALOG_IMPORTED_LAYERS::UnwrapRequired( const wxString& aLayerName )
{
if( !aLayerName.EndsWith( " *" ) )
return aLayerName;
return aLayerName.Left( aLayerName.Length() - 2 );
}
const INPUT_LAYER_DESC* DIALOG_IMPORTED_LAYERS::GetLayerDescription(
const wxString& aLayerName ) const
{
wxString layerName = UnwrapRequired( aLayerName );
for( const INPUT_LAYER_DESC& layerDescription : m_input_layers )
{
if( layerDescription.Name == layerName )
return &layerDescription;
}
return nullptr;
}
PCB_LAYER_ID DIALOG_IMPORTED_LAYERS::GetSelectedLayerID()
{
@ -58,11 +82,15 @@ PCB_LAYER_ID DIALOG_IMPORTED_LAYERS::GetSelectedLayerID()
PCB_LAYER_ID DIALOG_IMPORTED_LAYERS::GetAutoMatchLayerID( wxString aInputLayerName )
{
wxString pureInputLayerName = UnwrapRequired( aInputLayerName );
for( INPUT_LAYER_DESC inputLayerDesc : m_input_layers )
{
if( inputLayerDesc.Name == aInputLayerName )
if( inputLayerDesc.Name == pureInputLayerName
&& inputLayerDesc.AutoMapLayer != PCB_LAYER_ID::UNSELECTED_LAYER )
{
return inputLayerDesc.AutoMapLayer;
}
}
return PCB_LAYER_ID::UNDEFINED_LAYER;
}
@ -90,7 +118,8 @@ void DIALOG_IMPORTED_LAYERS::AddMappings()
long newItemIndex = m_matched_layers_list->InsertItem( 0, selectedLayerName );
m_matched_layers_list->SetItem( newItemIndex, 1, kiName );
m_matched_layers_map.insert( { selectedLayerName, selectedKiCadLayerID } );
m_matched_layers_map.insert(
{ UnwrapRequired( selectedLayerName ), selectedKiCadLayerID } );
// remove selected layer from vector and also GUI list
for( auto iter = m_unmatched_layer_names.begin(); iter != m_unmatched_layer_names.end();
@ -122,11 +151,12 @@ void DIALOG_IMPORTED_LAYERS::RemoveMappings( int aStatus )
!= wxNOT_FOUND )
{
wxString selectedLayerName = m_matched_layers_list->GetItemText( itemIndex, 0 );
wxString pureSelectedLayerName = UnwrapRequired( selectedLayerName );
wxCHECK( m_matched_layers_map.find( selectedLayerName ) != m_matched_layers_map.end(),
wxCHECK( m_matched_layers_map.find( pureSelectedLayerName ) != m_matched_layers_map.end(),
/*void*/ );
m_matched_layers_map.erase( selectedLayerName );
m_matched_layers_map.erase( pureSelectedLayerName );
rowsToDelete.Add( itemIndex );
m_unmatched_layers_list->InsertItem( 0, selectedLayerName );
@ -169,7 +199,7 @@ void DIALOG_IMPORTED_LAYERS::OnAutoMatchLayersClicked( wxCommandEvent& event )
long newItemIndex = m_matched_layers_list->InsertItem( 0, layerName );
m_matched_layers_list->SetItem( newItemIndex, 1, kiName );
m_matched_layers_map.insert( { layerName, autoMatchLayer } );
m_matched_layers_map.insert( { UnwrapRequired( layerName ), autoMatchLayer } );
// remove selected layer from vector and also GUI list
for( auto iter = m_unmatched_layer_names.begin(); iter != m_unmatched_layer_names.end();
@ -199,11 +229,12 @@ DIALOG_IMPORTED_LAYERS::DIALOG_IMPORTED_LAYERS( wxWindow* aParent,
for( INPUT_LAYER_DESC inLayer : aLayerDesc )
{
m_input_layers.push_back( inLayer );
m_unmatched_layer_names.push_back( inLayer.Name );
wxString layerName = inLayer.Required ? WrapRequired( inLayer.Name ) : inLayer.Name;
m_unmatched_layer_names.push_back( layerName );
kiCadLayers |= inLayer.PermittedLayers;
}
int maxTextWidth = 0;
int maxTextWidth = GetTextExtent( _( "Imported Layer" ) ).x;
for( const INPUT_LAYER_DESC& layer : m_input_layers )
maxTextWidth = std::max( maxTextWidth, GetTextExtent( layer.Name ).x );
@ -268,8 +299,21 @@ DIALOG_IMPORTED_LAYERS::DIALOG_IMPORTED_LAYERS( wxWindow* aParent,
FinishDialogSettings();
}
std::vector<wxString> DIALOG_IMPORTED_LAYERS::GetUnmappedRequiredLayers() const
{
std::vector<wxString> unmappedLayers;
for( const wxString& layerName : m_unmatched_layer_names )
{
const INPUT_LAYER_DESC* layerDesc = GetLayerDescription( layerName );
wxASSERT_MSG( layerDesc != nullptr, "Expected to find layer decription" );
if( layerDesc->Required )
unmappedLayers.push_back( layerDesc->Name );
}
return unmappedLayers;
}
LAYER_MAP DIALOG_IMPORTED_LAYERS::GetMapModal( wxWindow* aParent,
std::map<wxString, PCB_LAYER_ID> DIALOG_IMPORTED_LAYERS::GetMapModal( wxWindow* aParent,
const std::vector<INPUT_LAYER_DESC>& aLayerDesc )
{
DIALOG_IMPORTED_LAYERS dlg( aParent, aLayerDesc );
@ -279,10 +323,11 @@ LAYER_MAP DIALOG_IMPORTED_LAYERS::GetMapModal( wxWindow* aParent,
{
dlg.ShowModal();
if( dlg.m_unmatched_layer_names.size() > 0 )
if( dlg.GetUnmappedRequiredLayers().size() > 0 )
{
wxMessageBox( _( "All layers must be matched. Please click on 'Auto-Matched Layers' "
"to automatically match the remaining layers." ),
wxMessageBox( _( "All required layers (marked with '*') must be matched. "
"Please click on 'Auto-Match Layers' to "
"automatically match the remaining layers" ),
_( "Unmatched Layers" ), wxICON_ERROR | wxOK );
}
else

View File

@ -22,7 +22,7 @@
#define DIALOG_IMPORTED_LAYERS_H
#include <dialog_imported_layers_base.h>
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h> // INPUT_LAYER_DESC
#include <plugins/common/plugin_common_layer_mapping.h>
class DIALOG_IMPORTED_LAYERS : public DIALOG_IMPORTED_LAYERS_BASE
@ -33,15 +33,21 @@ private:
std::vector<INPUT_LAYER_DESC> m_input_layers;
std::vector<wxString> m_unmatched_layer_names;
LAYER_MAP m_matched_layers_map;
std::map<wxString, PCB_LAYER_ID> m_matched_layers_map;
//Helper functions
PCB_LAYER_ID GetSelectedLayerID();
PCB_LAYER_ID GetAutoMatchLayerID( wxString aInputLayerName );
void AddMappings();
void RemoveMappings( int aStatus );
void DeleteListItems( const wxArrayInt& aRowsToDelete, wxListCtrl* aListCtrl );
const INPUT_LAYER_DESC* GetLayerDescription( const wxString& aLayerName ) const;
static wxString WrapRequired( const wxString& aLayerName );
static wxString UnwrapRequired( const wxString& aLayerName );
//Event Handlers
void OnAutoMatchLayersClicked( wxCommandEvent& event ) override;
@ -55,13 +61,19 @@ public:
DIALOG_IMPORTED_LAYERS( wxWindow* aParent, const std::vector<INPUT_LAYER_DESC>& aLayerDesc );
/**
* @brief Creates and shows a dialog (modal) and returns the data from it after completion.
* If the dialog is closed or cancel is pressed, returns an empty LAYER_MAP
* @brief Return a list of layers names that are required, but they are not mapped
*/
std::vector<wxString> GetUnmappedRequiredLayers() const;
/**
* @brief Creates and shows a dialog (modal) and returns the data from it
* after completion. If the dialog is closed or cancel is pressed, returns
* an empty map
* @param aParent Parent window for the invoked dialog.
* @param aLayerDesc
* @return Mapped layers
*/
static LAYER_MAP GetMapModal( wxWindow* aParent,
static std::map<wxString, PCB_LAYER_ID> GetMapModal( wxWindow* aParent,
const std::vector<INPUT_LAYER_DESC>& aLayerDesc );
};

View File

@ -50,6 +50,7 @@
#include <project/project_file.h>
#include <project/project_local_settings.h>
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h>
#include <plugins/eagle/eagle_plugin.h>
#include <dialogs/dialog_imported_layers.h>
@ -621,18 +622,13 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
PLUGIN::RELEASER pi( IO_MGR::PluginFind( pluginType ) );
if( pluginType == IO_MGR::CADSTAR_PCB_ARCHIVE )
LAYER_REMAPPABLE_PLUGIN* layerRemappable =
dynamic_cast< LAYER_REMAPPABLE_PLUGIN* >( (PLUGIN*) pi );
if ( layerRemappable )
{
// TODO: Generalise this so that it is applicable to all non-kicad plugins
CADSTAR_PCB_ARCHIVE_PLUGIN* cadstarPlugin = nullptr;
cadstarPlugin = dynamic_cast<CADSTAR_PCB_ARCHIVE_PLUGIN*>( (PLUGIN*) pi );
wxCHECK( cadstarPlugin, false );
cadstarPlugin->RegisterLayerMappingCallback(
std::bind( DIALOG_IMPORTED_LAYERS::GetMapModal, this, std::placeholders::_1 ) );
using namespace std::placeholders;
layerRemappable->RegisterLayerMappingCallback(
std::bind( DIALOG_IMPORTED_LAYERS::GetMapModal, this, _1 ) );
}
// This will rename the file if there is an autosave and the user want to recover

View File

@ -537,7 +537,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::remapUnsureLayers()
return;
// Callback:
LAYER_MAP reMappedLayers = mLayerMappingHandler( inputLayers );
std::map<wxString, PCB_LAYER_ID> reMappedLayers = mLayerMappingHandler( inputLayers );
for( std::pair<wxString, PCB_LAYER_ID> layerPair : reMappedLayers )
{

View File

@ -27,7 +27,7 @@
#define CADSTAR_PCB_ARCHIVE_LOADER_H_
#include <cadstar_pcb_archive_parser.h>
#include <cadstar_pcb_archive_plugin.h> // LAYER_MAPPING_HANDLER definition
#include <cadstar_pcb_archive_plugin.h>
#include <class_board.h>
#include <set>

View File

@ -30,10 +30,10 @@
#include <properties.h>
LAYER_MAP CADSTAR_PCB_ARCHIVE_PLUGIN::DefaultLayerMappingCallback(
std::map<wxString, PCB_LAYER_ID> CADSTAR_PCB_ARCHIVE_PLUGIN::DefaultLayerMappingCallback(
const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
{
LAYER_MAP retval;
std::map<wxString, PCB_LAYER_ID> retval;
// Just return a the auto-mapped layers
for( INPUT_LAYER_DESC layerDesc : aInputLayerDescriptionVector )
@ -48,7 +48,7 @@ LAYER_MAP CADSTAR_PCB_ARCHIVE_PLUGIN::DefaultLayerMappingCallback(
void CADSTAR_PCB_ARCHIVE_PLUGIN::RegisterLayerMappingCallback(
LAYER_MAPPING_HANDLER aLayerMappingHandler )
{
m_layer_mapping_handler = aLayerMappingHandler;
LAYER_REMAPPABLE_PLUGIN::RegisterLayerMappingCallback( aLayerMappingHandler );
m_show_layer_mapping_warnings = false; // only show warnings with default callback
}
@ -57,8 +57,9 @@ CADSTAR_PCB_ARCHIVE_PLUGIN::CADSTAR_PCB_ARCHIVE_PLUGIN()
{
m_board = nullptr;
m_props = nullptr;
m_layer_mapping_handler = CADSTAR_PCB_ARCHIVE_PLUGIN::DefaultLayerMappingCallback;
m_show_layer_mapping_warnings = true;
LAYER_REMAPPABLE_PLUGIN::RegisterLayerMappingCallback(
CADSTAR_PCB_ARCHIVE_PLUGIN::DefaultLayerMappingCallback );
}

View File

@ -30,45 +30,10 @@
#include <io_mgr.h>
#include <layers_id_colors_and_visibility.h> // PCB_LAYER_ID
#include <plugins/common/plugin_common_layer_mapping.h>
/**
* @brief Describes an imported layer and how it could be mapped to KiCad Layers
*/
struct INPUT_LAYER_DESC
{
wxString Name; ///< Imported layer name as displayed in original application.
LSET PermittedLayers; ///< KiCad layers that the imported layer can be mapped onto.
PCB_LAYER_ID AutoMapLayer; ///< Best guess as to what the equivalent KiCad layer might be.
INPUT_LAYER_DESC()
{
Name = wxEmptyString;
PermittedLayers = LSET();
AutoMapLayer = PCB_LAYER_ID::UNDEFINED_LAYER;
}
};
/**
* A CADSTAR layer name.
*/
typedef wxString INPUT_LAYER_NAME;
/**
* @brief Map of CADSTAR (INPUT_LAYER_NAME) to KiCad Layers.
* If the mapped KiCad layer is UNDEFINED_LAYER, then the CADSTAR layer will not
* be imported
*/
typedef std::map<INPUT_LAYER_NAME, PCB_LAYER_ID> LAYER_MAP;
/**
* @brief Pointer to a function that takes a map of Cadstar and KiCad layers
* and returns a re-mapped version. If the re-mapped layer
*/
typedef std::function<LAYER_MAP( const std::vector<INPUT_LAYER_DESC>& )> LAYER_MAPPING_HANDLER;
class CADSTAR_PCB_ARCHIVE_PLUGIN : public PLUGIN
class CADSTAR_PCB_ARCHIVE_PLUGIN : public PLUGIN, public LAYER_REMAPPABLE_PLUGIN
{
public:
// -----<PUBLIC PLUGIN API>--------------------------------------------------
@ -93,7 +58,7 @@ public:
* @param aInputLayerDescriptionVector
* @return Auto-mapped layers
*/
static LAYER_MAP DefaultLayerMappingCallback(
static std::map<wxString, PCB_LAYER_ID> DefaultLayerMappingCallback(
const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector );
/**
@ -101,7 +66,7 @@ public:
* layers occurs
* @param aLayerMappingHandler
*/
void RegisterLayerMappingCallback( LAYER_MAPPING_HANDLER aLayerMappingHandler );
void RegisterLayerMappingCallback( LAYER_MAPPING_HANDLER aLayerMappingHandler ) override;
CADSTAR_PCB_ARCHIVE_PLUGIN();
~CADSTAR_PCB_ARCHIVE_PLUGIN();
@ -109,7 +74,6 @@ public:
private:
const PROPERTIES* m_props;
BOARD* m_board;
LAYER_MAPPING_HANDLER m_layer_mapping_handler;
bool m_show_layer_mapping_warnings;
};

View File

@ -0,0 +1,80 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Jan Mrázek <email@honzamrazek.cz>
* Copyright (C) 2020 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
* Copyright (C) 2020 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 as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLUGIN_COMMON_LAYER_MAPPING_H
#define PLUGIN_COMMON_LAYER_MAPPING_H
#include <functional>
#include <io_mgr.h>
#include <layers_id_colors_and_visibility.h> // PCB_LAYER_ID
/**
* @brief Describes an imported layer and how it could be mapped to KiCad Layers
*/
struct INPUT_LAYER_DESC
{
wxString Name; ///< Imported layer name as displayed in original application.
LSET PermittedLayers; ///< KiCad layers that the imported layer can be mapped onto.
PCB_LAYER_ID AutoMapLayer; ///< Best guess as to what the equivalent KiCad layer might be.
bool Required; ///< Should we require the layer to be assigned?
INPUT_LAYER_DESC()
: Name( wxEmptyString ),
PermittedLayers(),
AutoMapLayer( PCB_LAYER_ID::UNDEFINED_LAYER ),
Required( true )
{
}
};
/**
* @brief Pointer to a function that takes a map of source and KiCad layers
* and returns a re-mapped version. If the re-mapped layer is UNDEFINED_LAYER,
* then the source layer will not be imported
*/
using LAYER_MAPPING_HANDLER = std::function<std::map<wxString, PCB_LAYER_ID>( const std::vector<INPUT_LAYER_DESC>& )>;
/**
* @brief Plugin class for import plugins that support remappable layers
*/
class LAYER_REMAPPABLE_PLUGIN
{
public:
/**
* @brief Register a different handler to be called when mapping of input
* layers to KiCad layers occurs
*
* The function is marked as virtual, so the plugins can implement extra
* logic (e.g., enable warnings or checks)
*
* @param aLayerMappingHandler
*/
virtual void RegisterLayerMappingCallback( LAYER_MAPPING_HANDLER aLayerMappingHandler )
{
m_layer_mapping_handler = aLayerMappingHandler;
}
protected:
LAYER_MAPPING_HANDLER m_layer_mapping_handler; ///< Callback to get layer mapping
};
#endif // PLUGIN_COMMON_LAYER_MAPPING_H

View File

@ -274,8 +274,12 @@ EAGLE_PLUGIN::EAGLE_PLUGIN() :
m_xpath( new XPATH() ),
m_mod_time( wxDateTime::Now() )
{
using namespace std::placeholders;
init( NULL );
clear_cu_map();
RegisterLayerMappingCallback( std::bind(
&EAGLE_PLUGIN::DefaultLayerMappingCallback, this, _1 ) );
}
@ -298,7 +302,6 @@ const wxString EAGLE_PLUGIN::GetFileExtension() const
return wxT( "brd" );
}
wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d, int aTextThickness ) const
{
// Eagle includes stroke thickness in the text size, KiCAD does not
@ -453,6 +456,7 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
wxXmlNode* layers = drawingChildren["layers"];
loadLayerDefs( layers );
mapEagleLayersToKicad();
m_xpath->pop();
}
@ -501,11 +505,13 @@ void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
wxXmlNode* layerNode = aLayers->GetChildren();
m_eagleLayers.clear();
m_eagleLayersIds.clear();
while( layerNode )
{
ELAYER elayer( layerNode );
m_eagleLayers.insert( std::make_pair( elayer.number, elayer ) );
m_eagleLayersIds.insert( std::make_pair( elayer.name, elayer.number ) );
// find the subset of layers that are copper and active
if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
@ -1245,6 +1251,15 @@ ZONE* EAGLE_PLUGIN::loadPolygon( wxXmlNode* aPolyNode )
|| p.layer == EAGLE_LAYER::BRESTRICT
|| p.layer == EAGLE_LAYER::VRESTRICT );
if( layer == UNDEFINED_LAYER ) {
wxLogMessage( wxString::Format(
_( "Ignoring a polygon since Eagle layer '%s' (%d) "
"was not mapped" ),
eagle_layer_name( p.layer ),
p.layer ) );
return nullptr;
}
if( !IsCopperLayer( layer ) && !keepout )
return nullptr;
@ -1583,6 +1598,15 @@ void EAGLE_PLUGIN::packageWire( MODULE* aModule, wxXmlNode* aTree ) const
wxPoint end( kicad_x( w.x2 ), kicad_y( w.y2 ) );
int width = w.width.ToPcbUnits();
if( layer == UNDEFINED_LAYER ) {
wxLogMessage( wxString::Format(
_( "Ignoring a wire since Eagle layer '%s' (%d) "
"was not mapped" ),
eagle_layer_name( w.layer ),
w.layer ) );
return;
}
// KiCad cannot handle zero or negative line widths which apparently have meaning in Eagle.
if( width <= 0 )
{
@ -1747,8 +1771,14 @@ void EAGLE_PLUGIN::packageText( MODULE* aModule, wxXmlNode* aTree ) const
ETEXT t( aTree );
PCB_LAYER_ID layer = kicad_layer( t.layer );
if( layer == UNDEFINED_LAYER )
layer = Cmts_User;
if( layer == UNDEFINED_LAYER ) {
wxLogMessage( wxString::Format(
_( "Ignoring a text since Eagle layer '%s' (%d) "
"was not mapped" ),
eagle_layer_name( t.layer ),
t.layer ) );
return;
}
FP_TEXT* txt;
@ -1878,6 +1908,15 @@ void EAGLE_PLUGIN::packageRectangle( MODULE* aModule, wxXmlNode* aTree ) const
else
{
PCB_LAYER_ID layer = kicad_layer( r.layer );
if( layer == UNDEFINED_LAYER ) {
wxLogMessage( wxString::Format(
_( "Ignoring a rectange since Eagle layer '%s' (%d) "
"was not mapped" ),
eagle_layer_name( r.layer ),
r.layer ) );
return;
}
FP_SHAPE* dwg = new FP_SHAPE( aModule, S_POLYGON );
aModule->Add( dwg );
@ -1983,6 +2022,15 @@ void EAGLE_PLUGIN::packagePolygon( MODULE* aModule, wxXmlNode* aTree ) const
else
{
PCB_LAYER_ID layer = kicad_layer( p.layer );
if( layer == UNDEFINED_LAYER ) {
wxLogMessage( wxString::Format(
_( "Ignoring a polygon since Eagle layer '%s' (%d) "
"was not mapped" ),
eagle_layer_name( p.layer ),
p.layer ) );
return;
}
FP_SHAPE* dwg = new FP_SHAPE( aModule, S_POLYGON );
aModule->Add( dwg );
@ -2043,6 +2091,15 @@ void EAGLE_PLUGIN::packageCircle( MODULE* aModule, wxXmlNode* aTree ) const
else
{
PCB_LAYER_ID layer = kicad_layer( e.layer );
if( layer == UNDEFINED_LAYER ) {
wxLogMessage( wxString::Format(
_( "Ignoring a cricle since Eagle layer '%s' (%d) "
"was not mapped" ),
eagle_layer_name( e.layer ),
e.layer ) );
return;
}
FP_SHAPE* gr = new FP_SHAPE( aModule, S_CIRCLE );
// with == 0 means filled circle
@ -2451,78 +2508,172 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
m_xpath->pop(); // "signals.signal"
}
std::map<wxString, PCB_LAYER_ID> EAGLE_PLUGIN::DefaultLayerMappingCallback(
const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
{
std::map<wxString, PCB_LAYER_ID> layer_map;
for ( const INPUT_LAYER_DESC& layer : aInputLayerDescriptionVector )
{
PCB_LAYER_ID layerId = std::get<0>( defaultKicadLayer( eagle_layer_id( layer.Name ) ) );
layer_map.emplace( layer.Name, layerId );
}
return layer_map;
}
void EAGLE_PLUGIN::mapEagleLayersToKicad()
{
std::vector<INPUT_LAYER_DESC> inputDescs;
for ( const std::pair<int, ELAYER>& layerPair : m_eagleLayers )
{
const ELAYER& eLayer = layerPair.second;
INPUT_LAYER_DESC layerDesc;
std::tie( layerDesc.AutoMapLayer, layerDesc.PermittedLayers, layerDesc.Required ) =
defaultKicadLayer( eLayer.number );
if( layerDesc.AutoMapLayer == UNDEFINED_LAYER )
continue; // Ignore unused copper layers
layerDesc.Name = eLayer.name;
inputDescs.push_back( layerDesc );
}
m_layer_map = m_layer_mapping_handler( inputDescs );
}
PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const
{
int kiLayer;
auto result = m_layer_map.find( eagle_layer_name( aEagleLayer ) );
return result == m_layer_map.end() ? UNDEFINED_LAYER : result->second;
}
std::tuple<PCB_LAYER_ID, LSET, bool> EAGLE_PLUGIN::defaultKicadLayer( int aEagleLayer ) const
{
// eagle copper layer:
if( aEagleLayer >= 1 && aEagleLayer < int( arrayDim( m_cu_map ) ) )
{
kiLayer = m_cu_map[aEagleLayer];
LSET copperLayers;
for( int copperLayer : m_cu_map )
{
if( copperLayer >= 0 )
copperLayers[copperLayer] = true;
}
else
{
return { PCB_LAYER_ID( m_cu_map[aEagleLayer] ), copperLayers, true };
}
int kiLayer = UNSELECTED_LAYER;
bool required = false;
LSET permittedLayers;
permittedLayers.set();
// translate non-copper eagle layer to pcbnew layer
switch( aEagleLayer )
{
// Eagle says "Dimension" layer, but it's for board perimeter
case EAGLE_LAYER::DIMENSION: kiLayer = Edge_Cuts; break;
case EAGLE_LAYER::DIMENSION:
kiLayer = Edge_Cuts;
required = true;
permittedLayers = LSET( 1, Edge_Cuts );
break;
case EAGLE_LAYER::TPLACE: kiLayer = F_SilkS; break;
case EAGLE_LAYER::BPLACE: kiLayer = B_SilkS; break;
case EAGLE_LAYER::TNAMES: kiLayer = F_SilkS; break;
case EAGLE_LAYER::BNAMES: kiLayer = B_SilkS; break;
case EAGLE_LAYER::TVALUES: kiLayer = F_Fab; break;
case EAGLE_LAYER::BVALUES: kiLayer = B_Fab; break;
case EAGLE_LAYER::TSTOP: kiLayer = F_Mask; break;
case EAGLE_LAYER::BSTOP: kiLayer = B_Mask; break;
case EAGLE_LAYER::TCREAM: kiLayer = F_Paste; break;
case EAGLE_LAYER::BCREAM: kiLayer = B_Paste; break;
case EAGLE_LAYER::TFINISH: kiLayer = F_Mask; break;
case EAGLE_LAYER::BFINISH: kiLayer = B_Mask; break;
case EAGLE_LAYER::TGLUE: kiLayer = F_Adhes; break;
case EAGLE_LAYER::BGLUE: kiLayer = B_Adhes; break;
case EAGLE_LAYER::DOCUMENT: kiLayer = Cmts_User; break;
case EAGLE_LAYER::REFERENCELC: kiLayer = Cmts_User; break;
case EAGLE_LAYER::REFERENCELS: kiLayer = Cmts_User; break;
case EAGLE_LAYER::TPLACE:
kiLayer = F_SilkS;
break;
case EAGLE_LAYER::BPLACE:
kiLayer = B_SilkS;
break;
case EAGLE_LAYER::TNAMES:
kiLayer = F_SilkS;
break;
case EAGLE_LAYER::BNAMES:
kiLayer = B_SilkS;
break;
case EAGLE_LAYER::TVALUES:
kiLayer = F_Fab;
break;
case EAGLE_LAYER::BVALUES:
kiLayer = B_Fab;
break;
case EAGLE_LAYER::TSTOP:
kiLayer = F_Mask;
break;
case EAGLE_LAYER::BSTOP:
kiLayer = B_Mask;
break;
case EAGLE_LAYER::TCREAM:
kiLayer = F_Paste;
break;
case EAGLE_LAYER::BCREAM:
kiLayer = B_Paste;
break;
case EAGLE_LAYER::TFINISH:
kiLayer = F_Mask;
break;
case EAGLE_LAYER::BFINISH:
kiLayer = B_Mask;
break;
case EAGLE_LAYER::TGLUE:
kiLayer = F_Adhes;
break;
case EAGLE_LAYER::BGLUE:
kiLayer = B_Adhes;
break;
case EAGLE_LAYER::DOCUMENT:
kiLayer = Cmts_User;
break;
case EAGLE_LAYER::REFERENCELC:
kiLayer = Cmts_User;
break;
case EAGLE_LAYER::REFERENCELS:
kiLayer = Cmts_User;
break;
// Packages show the future chip pins on SMD parts using layer 51.
// This is an area slightly smaller than the PAD/SMD copper area.
// Carry those visual aids into the MODULE on the fabrication layer,
// not silkscreen. This is perhaps not perfect, but there is not a lot
// of other suitable paired layers
case EAGLE_LAYER::TDOCU: kiLayer = F_Fab; break;
case EAGLE_LAYER::BDOCU: kiLayer = B_Fab; break;
case EAGLE_LAYER::TDOCU:
kiLayer = F_Fab;
break;
case EAGLE_LAYER::BDOCU:
kiLayer = B_Fab;
break;
// these layers are defined as user layers. put them on ECO layers
case EAGLE_LAYER::USERLAYER1: kiLayer = Eco1_User; break;
case EAGLE_LAYER::USERLAYER2: kiLayer = Eco2_User; break;
case EAGLE_LAYER::USERLAYER1:
kiLayer = Eco1_User;
break;
case EAGLE_LAYER::USERLAYER2:
kiLayer = Eco2_User;
break;
// these will also appear in the ratsnest, so there's no need for a warning
case EAGLE_LAYER::UNROUTED: kiLayer = Dwgs_User; break;
case EAGLE_LAYER::UNROUTED:
kiLayer = Dwgs_User;
break;
case EAGLE_LAYER::TKEEPOUT: kiLayer = F_CrtYd; break;
case EAGLE_LAYER::BKEEPOUT: kiLayer = B_CrtYd; break;
case EAGLE_LAYER::TKEEPOUT:
kiLayer = F_CrtYd;
break;
case EAGLE_LAYER::BKEEPOUT:
kiLayer = B_CrtYd;
break;
case EAGLE_LAYER::MILLING:
case EAGLE_LAYER::TTEST:
case EAGLE_LAYER::BTEST:
case EAGLE_LAYER::HOLES:
default:
// some layers do not map to KiCad
wxLogMessage( wxString::Format( _( "Unsupported Eagle layer '%s' (%d), "
"converted to Dwgs.User layer" ),
eagle_layer_name( aEagleLayer ),
aEagleLayer ) );
kiLayer = Dwgs_User;
kiLayer = UNSELECTED_LAYER;
break;
}
}
return PCB_LAYER_ID( kiLayer );
return { PCB_LAYER_ID( kiLayer ), permittedLayers, required };
}
@ -2534,6 +2685,14 @@ const wxString& EAGLE_PLUGIN::eagle_layer_name( int aLayer ) const
}
int EAGLE_PLUGIN::eagle_layer_id( const wxString& aLayerName ) const
{
static const int unknown = -1;
auto it = m_eagleLayersIds.find( aLayerName );
return it == m_eagleLayersIds.end() ? unknown : it->second;
}
void EAGLE_PLUGIN::centerBoard()
{
if( m_props )

View File

@ -28,8 +28,10 @@
#include <io_mgr.h>
#include <layers_id_colors_and_visibility.h>
#include <plugins/eagle/eagle_parser.h>
#include <plugins/common/plugin_common_layer_mapping.h>
#include <map>
#include <tuple>
#include <wx/xml/xml.h>
class D_PAD;
@ -115,7 +117,7 @@ struct ERULES
* works with Eagle 6.x XML board files and footprints to implement the
* Pcbnew PLUGIN API, or a portion of it.
*/
class EAGLE_PLUGIN : public PLUGIN
class EAGLE_PLUGIN : public PLUGIN, public LAYER_REMAPPABLE_PLUGIN
{
public:
@ -164,12 +166,27 @@ public:
EAGLE_PLUGIN();
~EAGLE_PLUGIN();
/**
* @brief Default callback - just returns the automapped layers
*
* The callback needs to have the context of the current board so it can
* correctly determine copper layer mapping. Thus, it is not static and is
* expected to be bind to an instance of EAGLE_PLUGIN.
*
* @param aInputLayerDescriptionVector
* @return Auto-mapped layers
*/
std::map<wxString, PCB_LAYER_ID> DefaultLayerMappingCallback(
const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector );
private:
typedef std::vector<ELAYER> ELAYERS;
typedef ELAYERS::const_iterator EITER;
int m_cu_map[17]; ///< map eagle to kicad, cu layers only.
std::map<int, ELAYER> m_eagleLayers; ///< Eagle layers data stored by the layer number
std::map<wxString, int> m_eagleLayersIds; ///< Eagle layers id stored by the layer name
std::map<wxString, PCB_LAYER_ID> m_layer_map; ///< Mapping of Eagle layers to KiCAD layers
ERULES* m_rules; ///< Eagle design rules.
XPATH* m_xpath; ///< keeps track of what we are working on within
@ -207,12 +224,22 @@ private:
/// create a font size (fontz) from an eagle font size scalar and KiCAD font thickness
wxSize kicad_fontz( const ECOORD& d, int aTextThickness ) const;
/// Generate mapping between Eagle na KiCAD layers
void mapEagleLayersToKicad();
/// Convert an Eagle layer to a KiCad layer.
PCB_LAYER_ID kicad_layer( int aLayer ) const;
/// Get default KiCAD layer corresponding to an Eagle layer of the board,
/// a set of sensible layer mapping options and required flag
std::tuple<PCB_LAYER_ID, LSET, bool> defaultKicadLayer( int aEagleLayer ) const;
/// Get Eagle layer name by its number
const wxString& eagle_layer_name( int aLayer ) const;
/// Get Eagle leayer number by its name
int eagle_layer_id( const wxString& aLayerName ) const;
/// This PLUGIN only caches one footprint library, this determines which one.
void cacheLib( const wxString& aLibraryPath );