Eagle schematic importer improvements.

Change Eagle file importer to use a two pass import.  The first pass
parses the entire Eagle file into an associated E* object.  The second
pass converts the parsed E* objects into the appropriate KiCad objects.

Improve handling of Eagle versioned libraries.

Add helpers to IO_BASE to ease handling of PROGRESS_REPORTER and REPORTER
objects.

ADDED: Support for importing Eagle schematic modules.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/1813
This commit is contained in:
Wayne Stambaugh 2024-04-09 16:13:58 -04:00
parent e0e837189d
commit 889931505b
8 changed files with 3949 additions and 1463 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,9 @@
#include <unordered_set> #include <unordered_set>
#include <io/io_base.h> #include <io/io_base.h>
#include <progress_reporter.h>
#include <ki_exception.h> #include <ki_exception.h>
#include <reporter.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <wx/filename.h> #include <wx/filename.h>
@ -115,3 +117,24 @@ bool IO_BASE::CanReadLibrary( const wxString& aFileName ) const
return false; return false;
} }
void IO_BASE::Report( const wxString& aText, SEVERITY aSeverity )
{
if( !m_reporter )
return;
m_reporter->Report( aText, aSeverity );
}
void IO_BASE::AdvanceProgressPhase()
{
if( !m_progressReporter )
return;
if( !m_progressReporter->KeepRefreshing() )
THROW_IO_ERROR( _( "Loading file canceled by user." ) );
m_progressReporter->AdvancePhase();
}

View File

@ -57,6 +57,7 @@ const wxChar* const traceGalProfile = wxT( "KICAD_GAL_PROFILE" );
const wxChar* const traceKiCad2Step = wxT( "KICAD2STEP" ); const wxChar* const traceKiCad2Step = wxT( "KICAD2STEP" );
const wxChar* const traceUiProfile = wxT( "KICAD_UI_PROFILE" ); const wxChar* const traceUiProfile = wxT( "KICAD_UI_PROFILE" );
const wxChar* const traceGit = wxT( "KICAD_GIT" ); const wxChar* const traceGit = wxT( "KICAD_GIT" );
const wxChar* const traceEagleIo = wxT( "KICAD_EAGLE_IO" );
wxString dump( const wxArrayString& aArray ) wxString dump( const wxArrayString& aArray )

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* 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.
* *
* Copyright (C) 2017 CERN * Copyright (C) 2017 CERN
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
* *
* @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com> * @author Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
@ -31,7 +31,6 @@
#include <io/eagle/eagle_parser.h> #include <io/eagle/eagle_parser.h>
#include <geometry/seg.h> #include <geometry/seg.h>
#include <boost/ptr_container/ptr_map.hpp>
class EDA_TEXT; class EDA_TEXT;
class KIWAY; class KIWAY;
@ -58,19 +57,24 @@ class wxXmlNode;
struct EAGLE_LIBRARY struct EAGLE_LIBRARY
{ {
wxString name; wxString name;
boost::ptr_map<wxString, LIB_SYMBOL> KiCadSymbols; std::map<wxString, std::unique_ptr<LIB_SYMBOL>> KiCadSymbols;
std::unordered_map<wxString, wxXmlNode*> SymbolNodes;
std::unordered_map<wxString, int> GateUnit; /**
* Map Eagle gate unit number (which are strings) to KiCad library symbol unit number.
*
* The look up name is #EDEVICE name + #EDEVICE name + #EGATE name separated by underscores.
* Hashing would be faster but it would be nearly impossible to debug so use string look up
* for now.
*/
std::unordered_map<wxString, int> GateToUnitMap;
std::unordered_map<wxString, wxString> package; std::unordered_map<wxString, wxString> package;
}; };
typedef boost::ptr_map<wxString, EPART> EPART_LIST;
/** /**
* A #SCH_IO derivation for loading 6.x+ Eagle schematic files. * A #SCH_IO derivation for loading 6.x+ Eagle schematic files.
* *
* As with all SCH_IO there is no UI dependencies i.e. windowing calls allowed. * As with all #SCH_IO objects there are no UI dependencies i.e. windowing calls allowed.
*/ */
class SCH_IO_EAGLE : public SCH_IO class SCH_IO_EAGLE : public SCH_IO
{ {
@ -111,20 +115,22 @@ public:
bool IsLibraryWritable( const wxString& aLibraryPath ) override { return false; } bool IsLibraryWritable( const wxString& aLibraryPath ) override { return false; }
private: private:
void checkpoint();
bool checkHeader( const wxString& aFileName ) const; bool checkHeader( const wxString& aFileName ) const;
wxXmlDocument loadXmlDocument( const wxString& aFileName ); wxXmlDocument loadXmlDocument( const wxString& aFileName );
long long getLibraryTimestamp( const wxString& aLibraryPath ) const; long long getLibraryTimestamp( const wxString& aLibraryPath ) const;
void ensureLoadedLibrary( const wxString& aLibraryPath ); void ensureLoadedLibrary( const wxString& aLibraryPath );
void loadDrawing( wxXmlNode* aDrawingNode ); void loadDrawing( const std::unique_ptr<EDRAWING>& aDrawing );
void loadLayerDefs( wxXmlNode* aLayers ); void loadLayerDefs( const std::vector<std::unique_ptr<ELAYER>>& aLayers );
void loadSchematic( wxXmlNode* aSchematicNode ); void loadSchematic( const ESCHEMATIC& aSchematic );
void loadSheet( wxXmlNode* aSheetNode, int sheetcount ); void loadSheet( const std::unique_ptr<ESHEET>& aSheet );
void loadInstance( wxXmlNode* aInstanceNode ); void loadInstance( const std::unique_ptr<EINSTANCE>& aInstance,
EAGLE_LIBRARY* loadLibrary( wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLib ); const std::map<wxString, std::unique_ptr<EPART>>& aParts );
void countNets( wxXmlNode* aSchematicNode );
SCH_SHEET* loadModuleInstance( const std::unique_ptr<EMODULEINST>& aModuleInstance );
EAGLE_LIBRARY* loadLibrary( const ELIBRARY* aLibrary, EAGLE_LIBRARY* aEagleLib );
void countNets( const ESCHEMATIC& aSchematic );
/// Move any labels on the wire to the new end point of the wire. /// Move any labels on the wire to the new end point of the wire.
void moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint ); void moveLabels( SCH_LINE* aWire, const VECTOR2I& aNewEndPoint );
@ -139,29 +145,41 @@ private:
std::pair<VECTOR2I, const SEG*> findNearestLinePoint( const VECTOR2I& aPoint, std::pair<VECTOR2I, const SEG*> findNearestLinePoint( const VECTOR2I& aPoint,
const std::vector<SEG>& aLines ) const; const std::vector<SEG>& aLines ) const;
void loadSegments( wxXmlNode* aSegmentsNode, const wxString& aNetName, void loadSegments( const std::vector<std::unique_ptr<ESEGMENT>>& aSegments,
const wxString& aNetName,
const wxString& aNetClass ); const wxString& aNetClass );
SCH_SHAPE* loadPolyLine( wxXmlNode* aPolygonNode ); SCH_SHAPE* loadPolyLine( const std::unique_ptr<EPOLYGON>& aPolygon );
SCH_ITEM* loadWire( wxXmlNode* aWireNode, SEG& endpoints ); SCH_ITEM* loadWire( const std::unique_ptr<EWIRE>& aWire, SEG& endpoints );
SCH_SHAPE* loadCircle( wxXmlNode* aCircleNode ); SCH_SHAPE* loadCircle( const std::unique_ptr<ECIRCLE>& aCircle );
SCH_SHAPE* loadRectangle( wxXmlNode* aRectNode ); SCH_SHAPE* loadRectangle( const std::unique_ptr<ERECT>& aRect );
SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName ); SCH_TEXT* loadLabel( const std::unique_ptr<ELABEL>& aLabel, const wxString& aNetName );
SCH_JUNCTION* loadJunction( wxXmlNode* aJunction ); SCH_JUNCTION* loadJunction( const std::unique_ptr<EJUNCTION>& aJunction );
SCH_TEXT* loadPlainText( wxXmlNode* aSchText ); SCH_TEXT* loadPlainText( const std::unique_ptr<ETEXT>& aSchText );
void loadFrame( wxXmlNode* aFrameNode, std::vector<SCH_ITEM*>& aItems ); void loadFrame( const std::unique_ptr<EFRAME>& aFrame,
std::vector<SCH_ITEM*>& aItems );
bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_SYMBOL>& aSymbol, bool loadSymbol( const std::unique_ptr<ESYMBOL>& aEsymbol,
EDEVICE* aDevice, int aGateNumber, const wxString& aGateName ); std::unique_ptr<LIB_SYMBOL>& aSymbol,
SCH_SHAPE* loadSymbolCircle( wxXmlNode* aCircleNode, int aGateNumber ); const std::unique_ptr<EDEVICE>& aDevice, int aGateNumber,
SCH_SHAPE* loadSymbolRectangle( wxXmlNode* aRectNode, int aGateNumber ); const wxString& aGateName );
SCH_SHAPE* loadSymbolPolyLine( wxXmlNode* aPolygonNode, int aGateNumber ); SCH_SHAPE* loadSymbolCircle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
SCH_ITEM* loadSymbolWire( wxXmlNode* aWireNode, int aGateNumber ); const std::unique_ptr<ECIRCLE>& aCircle,
SCH_PIN* loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol, wxXmlNode*, EPIN* epin, int aGateNumber );
SCH_SHAPE* loadSymbolRectangle( std::unique_ptr<LIB_SYMBOL>& aSymbol,
const std::unique_ptr<ERECT>& aRectangle,
int aGateNumber );
SCH_SHAPE* loadSymbolPolyLine( std::unique_ptr<LIB_SYMBOL>& aSymbol,
const std::unique_ptr<EPOLYGON>& aPolygon, int aGateNumber );
SCH_ITEM* loadSymbolWire( std::unique_ptr<LIB_SYMBOL>& aSymbol,
const std::unique_ptr<EWIRE>& aWire,
int aGateNumber );
SCH_PIN* loadPin( std::unique_ptr<LIB_SYMBOL>& aSymbol, const std::unique_ptr<EPIN>& aPin,
int aGateNumber ); int aGateNumber );
SCH_TEXT* loadSymbolText( wxXmlNode* aLibText, int aGateNumber ); SCH_TEXT* loadSymbolText( std::unique_ptr<LIB_SYMBOL>& aSymbol,
void loadSymbolFrame( wxXmlNode* aFrameNode, std::vector<SCH_ITEM*>& aLines ); const std::unique_ptr<ETEXT>& aText,
int aGateNumber );
void loadTextAttributes( EDA_TEXT* aText, const ETEXT& aAttribs ) const; void loadTextAttributes( EDA_TEXT* aText,
const std::unique_ptr<ETEXT>& aAttributes ) const;
void loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const; void loadFieldAttributes( SCH_FIELD* aField, const SCH_TEXT* aText ) const;
///< Move net labels that are detached from any wire to the nearest wire ///< Move net labels that are detached from any wire to the nearest wire
@ -230,18 +248,19 @@ private:
wxFileName m_filename; wxFileName m_filename;
wxString m_libName; ///< Library name to save symbols wxString m_libName; ///< Library name to save symbols
SCHEMATIC* m_schematic; ///< Passed to Load(), the schematic object being loaded SCHEMATIC* m_schematic; ///< Passed to Load(), the schematic object being loaded
EMODULE* m_module; ///< The current module being loaded or nullptr
EPART_MAP m_partlist; std::map<wxString, const EPART*> m_partlist;
std::map<wxString, long long> m_timestamps; std::map<wxString, long long> m_timestamps;
std::map<wxString, EAGLE_LIBRARY> m_eagleLibs; std::map<wxString, EAGLE_LIBRARY> m_eagleLibs;
std::map<wxString, std::unique_ptr<EMODULE>> m_eagleModules;
std::unordered_map<wxString, bool> m_userValue; ///< deviceset/@uservalue for device. std::unordered_map<wxString, bool> m_userValue; ///< deviceset/@uservalue for device.
IO_RELEASER<SCH_IO> m_pi; ///< PI to create KiCad symbol library. IO_RELEASER<SCH_IO> m_pi; ///< PI to create KiCad symbol library.
std::unique_ptr<STRING_UTF8_MAP> m_properties; ///< Library plugin properties. std::unique_ptr<STRING_UTF8_MAP> m_properties; ///< Library plugin properties.
unsigned m_doneCount; int m_sheetIndex;
unsigned m_lastProgressCount;
unsigned m_totalCount; ///< for progress reporting
std::map<wxString, int> m_netCounts; std::map<wxString, int> m_netCounts;
std::map<int, SCH_LAYER_ID> m_layerMap; std::map<int, SCH_LAYER_ID> m_layerMap;
@ -270,6 +289,9 @@ private:
///< Positions of pins and wire endings mapped to its parent ///< Positions of pins and wire endings mapped to its parent
std::map<VECTOR2I, std::set<const EDA_ITEM*>> m_connPoints; std::map<VECTOR2I, std::set<const EDA_ITEM*>> m_connPoints;
///< The fully parsed Eagle schematic file.
std::unique_ptr<EAGLE_DOC> m_eagleDoc;
}; };
#endif // SCH_IO_EAGLE_H_ #endif // SCH_IO_EAGLE_H_

View File

@ -24,6 +24,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <wx/string.h> #include <wx/string.h>
#include <widgets/report_severity.h>
class REPORTER; class REPORTER;
class PROGRESS_REPORTER; class PROGRESS_REPORTER;
@ -187,6 +188,10 @@ public:
*/ */
virtual void GetLibraryOptions( STRING_UTF8_MAP* aListToAppendTo ) const; virtual void GetLibraryOptions( STRING_UTF8_MAP* aListToAppendTo ) const;
virtual void Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED );
virtual void AdvanceProgressPhase();
protected: protected:
// Delete the zero-argument base constructor to force proper construction // Delete the zero-argument base constructor to force proper construction
IO_BASE() = delete; IO_BASE() = delete;
@ -213,4 +218,4 @@ protected:
PROGRESS_REPORTER* m_progressReporter; PROGRESS_REPORTER* m_progressReporter;
}; };
#endif // IO_BASE_H_ #endif // IO_BASE_H_

View File

@ -234,6 +234,13 @@ extern KICOMMON_API const wxChar* const traceUiProfile;
*/ */
extern KICOMMON_API const wxChar* const traceGit; extern KICOMMON_API const wxChar* const traceGit;
/*
* Flag to enable Eagle I/O debug tracing.
*
* Use "KICAD_EAGLE_IO" to enable.
*/
extern KICOMMON_API const wxChar* const traceEagleIo;
///@} ///@}
/** /**