Read netclasses when importing Eagle projects.
Also creates a DRU file with the various netclass-to-netclass clearance rules from the Eagle clearance matrix. Fixes https://gitlab.com/kicad/code/kicad/issues/1774
This commit is contained in:
parent
aa85bb27fa
commit
f66654247a
|
@ -278,8 +278,9 @@ wxPoint ConvertArcCenter( const wxPoint& aStart, const wxPoint& aEnd, double aAn
|
||||||
|
|
||||||
if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
|
if( !std::isnormal( dlen ) || !std::isnormal( aAngle ) )
|
||||||
{
|
{
|
||||||
THROW_IO_ERROR(
|
THROW_IO_ERROR( wxString::Format( _( "Invalid Arc with radius %f and angle %f" ),
|
||||||
wxString::Format( _( "Invalid Arc with radius %f and angle %f" ), dlen, aAngle ) );
|
dlen,
|
||||||
|
aAngle ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
|
double dist = dlen / ( 2 * tan( DEG2RAD( aAngle ) / 2 ) );
|
||||||
|
@ -919,15 +920,14 @@ EPART::EPART( wxXmlNode* aPart )
|
||||||
technology = parseOptionalAttribute<wxString>( aPart, "technology" );
|
technology = parseOptionalAttribute<wxString>( aPart, "technology" );
|
||||||
value = parseOptionalAttribute<wxString>( aPart, "value" );
|
value = parseOptionalAttribute<wxString>( aPart, "value" );
|
||||||
|
|
||||||
for( auto child = aPart->GetChildren(); child; child = child->GetNext() )
|
for( wxXmlNode* child = aPart->GetChildren(); child; child = child->GetNext() )
|
||||||
{
|
{
|
||||||
|
|
||||||
if( child->GetName() == "attribute" )
|
if( child->GetName() == "attribute" )
|
||||||
{
|
{
|
||||||
std::string aname, avalue;
|
std::string aname, avalue;
|
||||||
for( auto x = child->GetAttributes(); x; x = x->GetNext() )
|
|
||||||
{
|
|
||||||
|
|
||||||
|
for( wxXmlAttribute* x = child->GetAttributes(); x; x = x->GetNext() )
|
||||||
|
{
|
||||||
if( x->GetName() == "name" )
|
if( x->GetName() == "name" )
|
||||||
aname = x->GetValue();
|
aname = x->GetValue();
|
||||||
else if( x->GetName() == "value" )
|
else if( x->GetName() == "value" )
|
||||||
|
@ -940,9 +940,9 @@ EPART::EPART( wxXmlNode* aPart )
|
||||||
else if( child->GetName() == "variant" )
|
else if( child->GetName() == "variant" )
|
||||||
{
|
{
|
||||||
std::string aname, avalue;
|
std::string aname, avalue;
|
||||||
for( auto x = child->GetAttributes(); x; x = x->GetNext() )
|
|
||||||
{
|
|
||||||
|
|
||||||
|
for( wxXmlAttribute* x = child->GetAttributes(); x; x = x->GetNext() )
|
||||||
|
{
|
||||||
if( x->GetName() == "name" )
|
if( x->GetName() == "name" )
|
||||||
aname = x->GetValue();
|
aname = x->GetValue();
|
||||||
else if( x->GetName() == "value" )
|
else if( x->GetName() == "value" )
|
||||||
|
@ -1077,7 +1077,7 @@ EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
|
||||||
>
|
>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
name = parseRequiredAttribute<wxString>(aDeviceSet, "name");
|
name = parseRequiredAttribute<wxString>( aDeviceSet, "name" );
|
||||||
prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
|
prefix = parseOptionalAttribute<wxString>( aDeviceSet, "prefix" );
|
||||||
uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
|
uservalue = parseOptionalAttribute<bool>( aDeviceSet, "uservalue" );
|
||||||
|
|
||||||
|
@ -1102,3 +1102,21 @@ EDEVICE_SET::EDEVICE_SET( wxXmlNode* aDeviceSet )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ECLASS::ECLASS( wxXmlNode* aClass )
|
||||||
|
{
|
||||||
|
number = parseRequiredAttribute<wxString>( aClass, "number" );
|
||||||
|
name = parseRequiredAttribute<wxString>( aClass, "name" );
|
||||||
|
|
||||||
|
for( wxXmlNode* child = aClass->GetChildren(); child; child = child->GetNext() )
|
||||||
|
{
|
||||||
|
if( child->GetName() == "clearance" )
|
||||||
|
{
|
||||||
|
wxString to = parseRequiredAttribute<wxString>( child, "class" );
|
||||||
|
ECOORD value = parseRequiredAttribute<ECOORD>( child, "value" );
|
||||||
|
|
||||||
|
clearanceMap[to] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1054,4 +1054,14 @@ struct EDEVICE_SET
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ECLASS
|
||||||
|
{
|
||||||
|
wxString number;
|
||||||
|
wxString name;
|
||||||
|
std::map<wxString, ECOORD> clearanceMap;
|
||||||
|
|
||||||
|
ECLASS( wxXmlNode* aClass );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _EAGLE_PARSER_H_
|
#endif // _EAGLE_PARSER_H_
|
||||||
|
|
|
@ -68,7 +68,7 @@ Load() TODO's
|
||||||
#include <trigo.h>
|
#include <trigo.h>
|
||||||
#include <math/util.h> // for KiROUND
|
#include <math/util.h> // for KiROUND
|
||||||
#include <progress_reporter.h>
|
#include <progress_reporter.h>
|
||||||
|
#include <project.h>
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
#include <board_design_settings.h>
|
#include <board_design_settings.h>
|
||||||
#include <footprint.h>
|
#include <footprint.h>
|
||||||
|
@ -402,13 +402,34 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
|
||||||
designSettings.m_ViasMinAnnularWidth = m_min_annulus;
|
designSettings.m_ViasMinAnnularWidth = m_min_annulus;
|
||||||
|
|
||||||
if( m_rules->mdWireWire )
|
if( m_rules->mdWireWire )
|
||||||
{
|
designSettings.m_MinClearance = KiROUND( m_rules->mdWireWire );
|
||||||
NETCLASS* defaultNetclass = designSettings.GetDefault();
|
|
||||||
int clearance = KiROUND( m_rules->mdWireWire );
|
|
||||||
|
|
||||||
if( clearance < defaultNetclass->GetClearance() )
|
NETCLASS defaults( "dummy" );
|
||||||
defaultNetclass->SetClearance( clearance );
|
|
||||||
}
|
auto finishNetclass =
|
||||||
|
[&]( NETCLASSPTR netclass )
|
||||||
|
{
|
||||||
|
if( netclass->GetTrackWidth() == INT_MAX )
|
||||||
|
netclass->SetTrackWidth( defaults.GetTrackWidth() );
|
||||||
|
|
||||||
|
if( netclass->GetViaDiameter() == INT_MAX )
|
||||||
|
netclass->SetViaDiameter( defaults.GetViaDiameter() );
|
||||||
|
|
||||||
|
if( netclass->GetViaDrill() == INT_MAX )
|
||||||
|
netclass->SetViaDrill( defaults.GetViaDrill() );
|
||||||
|
};
|
||||||
|
|
||||||
|
finishNetclass( designSettings.GetNetClasses().GetDefault() );
|
||||||
|
|
||||||
|
for( const std::pair<const wxString, NETCLASSPTR>& entry : designSettings.GetNetClasses() )
|
||||||
|
finishNetclass( entry.second );
|
||||||
|
|
||||||
|
m_board->m_LegacyNetclassesLoaded = true;
|
||||||
|
m_board->m_LegacyDesignSettingsLoaded = true;
|
||||||
|
|
||||||
|
fn.SetExt( "kicad_dru" );
|
||||||
|
wxFile rulesFile( fn.GetFullPath(), wxFile::write );
|
||||||
|
rulesFile.Write( m_customRules );
|
||||||
|
|
||||||
// should be empty, else missing m_xpath->pop()
|
// should be empty, else missing m_xpath->pop()
|
||||||
wxASSERT( m_xpath->Contents().size() == 0 );
|
wxASSERT( m_xpath->Contents().size() == 0 );
|
||||||
|
@ -507,6 +528,7 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
|
||||||
wxXmlNode* designrules = boardChildren["designrules"];
|
wxXmlNode* designrules = boardChildren["designrules"];
|
||||||
wxXmlNode* layers = drawingChildren["layers"];
|
wxXmlNode* layers = drawingChildren["layers"];
|
||||||
wxXmlNode* plain = boardChildren["plain"];
|
wxXmlNode* plain = boardChildren["plain"];
|
||||||
|
wxXmlNode* classes = boardChildren["classes"];
|
||||||
wxXmlNode* signals = boardChildren["signals"];
|
wxXmlNode* signals = boardChildren["signals"];
|
||||||
wxXmlNode* libs = boardChildren["libraries"];
|
wxXmlNode* libs = boardChildren["libraries"];
|
||||||
wxXmlNode* elems = boardChildren["elements"];
|
wxXmlNode* elems = boardChildren["elements"];
|
||||||
|
@ -555,6 +577,7 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
|
||||||
m_xpath->push( "board" );
|
m_xpath->push( "board" );
|
||||||
|
|
||||||
loadPlain( plain );
|
loadPlain( plain );
|
||||||
|
loadClasses( classes );
|
||||||
loadSignals( signals );
|
loadSignals( signals );
|
||||||
loadLibraries( libs );
|
loadLibraries( libs );
|
||||||
loadElements( elems );
|
loadElements( elems );
|
||||||
|
@ -2382,14 +2405,74 @@ void EAGLE_PLUGIN::deleteTemplates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EAGLE_PLUGIN::loadClasses( wxXmlNode* aClasses )
|
||||||
|
{
|
||||||
|
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
|
||||||
|
|
||||||
|
m_xpath->push( "classes.class", "number" );
|
||||||
|
|
||||||
|
std::vector<ECLASS> eClasses;
|
||||||
|
wxXmlNode* classNode = aClasses->GetChildren();
|
||||||
|
|
||||||
|
while( classNode )
|
||||||
|
{
|
||||||
|
checkpoint();
|
||||||
|
|
||||||
|
ECLASS eClass( classNode );
|
||||||
|
NETCLASSPTR netclass;
|
||||||
|
|
||||||
|
if( eClass.name.CmpNoCase( "default" ) == 0 )
|
||||||
|
{
|
||||||
|
netclass = bds.GetNetClasses().GetDefault();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netclass.reset( new NETCLASS( eClass.name ) );
|
||||||
|
m_board->GetDesignSettings().GetNetClasses().Add( netclass );
|
||||||
|
}
|
||||||
|
|
||||||
|
netclass->SetTrackWidth( INT_MAX );
|
||||||
|
netclass->SetViaDiameter( INT_MAX );
|
||||||
|
netclass->SetViaDrill( INT_MAX );
|
||||||
|
|
||||||
|
eClasses.emplace_back( eClass );
|
||||||
|
m_classMap[ eClass.number ] = netclass;
|
||||||
|
|
||||||
|
// Get next class
|
||||||
|
classNode = classNode->GetNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_customRules = "(version 1)";
|
||||||
|
|
||||||
|
for( ECLASS& eClass : eClasses )
|
||||||
|
{
|
||||||
|
for( std::pair<const wxString&, ECOORD> entry : eClass.clearanceMap )
|
||||||
|
{
|
||||||
|
wxString rule;
|
||||||
|
rule.Printf( "(rule \"class %s:%s\"\n"
|
||||||
|
" (condition \"A.NetClass == '%s' && B.NetClass == '%s'\")\n"
|
||||||
|
" (constraint clearance (min %smm)))\n",
|
||||||
|
eClass.number,
|
||||||
|
entry.first,
|
||||||
|
eClass.name,
|
||||||
|
m_classMap[ entry.first ]->GetName(),
|
||||||
|
StringFromValue( EDA_UNITS::MILLIMETRES, entry.second.ToPcbUnits() ) );
|
||||||
|
|
||||||
|
m_customRules += "\n" + rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_xpath->pop(); // "classes.class"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
||||||
{
|
{
|
||||||
ZONES zones; // per net
|
ZONES zones; // per net
|
||||||
|
int netCode = 1;
|
||||||
|
|
||||||
m_xpath->push( "signals.signal", "name" );
|
m_xpath->push( "signals.signal", "name" );
|
||||||
|
|
||||||
int netCode = 1;
|
|
||||||
|
|
||||||
// Get the first signal and iterate
|
// Get the first signal and iterate
|
||||||
wxXmlNode* net = aSignals->GetChildren();
|
wxXmlNode* net = aSignals->GetChildren();
|
||||||
|
|
||||||
|
@ -2402,7 +2485,18 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
||||||
zones.clear();
|
zones.clear();
|
||||||
|
|
||||||
const wxString& netName = escapeName( net->GetAttribute( "name" ) );
|
const wxString& netName = escapeName( net->GetAttribute( "name" ) );
|
||||||
m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) );
|
NETINFO_ITEM* netInfo = new NETINFO_ITEM( m_board, netName, netCode );
|
||||||
|
NETCLASSPTR netclass;
|
||||||
|
|
||||||
|
if( net->HasAttribute( "class" ) )
|
||||||
|
{
|
||||||
|
netclass = m_classMap[ net->GetAttribute( "class" ) ];
|
||||||
|
|
||||||
|
netclass->Add( netName );
|
||||||
|
netInfo->SetNetClass( netclass );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_board->Add( netInfo );
|
||||||
|
|
||||||
m_xpath->Value( netName.c_str() );
|
m_xpath->Value( netName.c_str() );
|
||||||
|
|
||||||
|
@ -2435,6 +2529,9 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
||||||
if( width < m_min_trace )
|
if( width < m_min_trace )
|
||||||
m_min_trace = width;
|
m_min_trace = width;
|
||||||
|
|
||||||
|
if( netclass && width < netclass->GetTrackWidth() )
|
||||||
|
netclass->SetTrackWidth( width );
|
||||||
|
|
||||||
if( w.curve )
|
if( w.curve )
|
||||||
{
|
{
|
||||||
center = ConvertArcCenter( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ),
|
center = ConvertArcCenter( wxPoint( kicad_x( w.x1 ), kicad_y( w.y1 ) ),
|
||||||
|
@ -2538,9 +2635,15 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
|
||||||
if( kidiam < m_min_via )
|
if( kidiam < m_min_via )
|
||||||
m_min_via = kidiam;
|
m_min_via = kidiam;
|
||||||
|
|
||||||
|
if( netclass && kidiam < netclass->GetViaDiameter() )
|
||||||
|
netclass->SetViaDiameter( kidiam );
|
||||||
|
|
||||||
if( drillz < m_min_hole )
|
if( drillz < m_min_hole )
|
||||||
m_min_hole = drillz;
|
m_min_hole = drillz;
|
||||||
|
|
||||||
|
if( netclass && drillz < netclass->GetViaDrill() )
|
||||||
|
netclass->SetViaDrill( drillz );
|
||||||
|
|
||||||
if( ( kidiam - drillz ) / 2 < m_min_annulus )
|
if( ( kidiam - drillz ) / 2 < m_min_annulus )
|
||||||
m_min_annulus = ( kidiam - drillz ) / 2;
|
m_min_annulus = ( kidiam - drillz ) / 2;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#ifndef EAGLE_PLUGIN_H_
|
|
||||||
#define EAGLE_PLUGIN_H_
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
|
@ -25,9 +22,13 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef EAGLE_PLUGIN_H
|
||||||
|
#define EAGLE_PLUGIN_H
|
||||||
|
|
||||||
#include <convert_to_biu.h>
|
#include <convert_to_biu.h>
|
||||||
#include <io_mgr.h>
|
#include <io_mgr.h>
|
||||||
#include <layer_ids.h>
|
#include <layer_ids.h>
|
||||||
|
#include <netclass.h>
|
||||||
#include <plugins/eagle/eagle_parser.h>
|
#include <plugins/eagle/eagle_parser.h>
|
||||||
#include <plugins/common/plugin_common_layer_mapping.h>
|
#include <plugins/common/plugin_common_layer_mapping.h>
|
||||||
|
|
||||||
|
@ -218,6 +219,7 @@ private:
|
||||||
void loadDesignRules( wxXmlNode* aDesignRules );
|
void loadDesignRules( wxXmlNode* aDesignRules );
|
||||||
void loadLayerDefs( wxXmlNode* aLayers );
|
void loadLayerDefs( wxXmlNode* aLayers );
|
||||||
void loadPlain( wxXmlNode* aPlain );
|
void loadPlain( wxXmlNode* aPlain );
|
||||||
|
void loadClasses( wxXmlNode* aClasses );
|
||||||
void loadSignals( wxXmlNode* aSignals );
|
void loadSignals( wxXmlNode* aSignals );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,6 +288,9 @@ private:
|
||||||
std::map<wxString, int> m_eagleLayersIds; ///< Eagle layer ids stored by layer name
|
std::map<wxString, int> m_eagleLayersIds; ///< Eagle layer ids stored by layer name
|
||||||
std::map<wxString, PCB_LAYER_ID> m_layer_map; ///< Map of Eagle layers to KiCad layers
|
std::map<wxString, PCB_LAYER_ID> m_layer_map; ///< Map of Eagle layers to KiCad layers
|
||||||
|
|
||||||
|
std::map<wxString, NETCLASSPTR> m_classMap; ///< Eagle class number to KiCad netclass
|
||||||
|
wxString m_customRules;
|
||||||
|
|
||||||
ERULES* m_rules; ///< Eagle design rules.
|
ERULES* m_rules; ///< Eagle design rules.
|
||||||
XPATH* m_xpath; ///< keeps track of what we are working on within
|
XPATH* m_xpath; ///< keeps track of what we are working on within
|
||||||
///< XML document during a Load().
|
///< XML document during a Load().
|
||||||
|
@ -299,8 +304,8 @@ private:
|
||||||
///< lookup key is either libname.packagename or simply
|
///< lookup key is either libname.packagename or simply
|
||||||
///< packagename if FootprintLoad() or FootprintEnumberate()
|
///< packagename if FootprintLoad() or FootprintEnumberate()
|
||||||
|
|
||||||
const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL.
|
const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL.
|
||||||
BOARD* m_board; ///< which BOARD is being worked on, no ownership here
|
BOARD* m_board; ///< which BOARD is being worked on, no ownership here
|
||||||
|
|
||||||
PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr
|
PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr
|
||||||
unsigned m_doneCount;
|
unsigned m_doneCount;
|
||||||
|
@ -316,4 +321,4 @@ private:
|
||||||
wxDateTime m_mod_time;
|
wxDateTime m_mod_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EAGLE_PLUGIN_H_
|
#endif // EAGLE_PLUGIN_H
|
||||||
|
|
Loading…
Reference in New Issue