From 404457f455b0ce87e597019a5b88d4f3eacfbaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Garc=C3=ADa=20Montoro?= Date: Mon, 8 May 2017 16:10:23 +0200 Subject: [PATCH] Eeschema Eagle plugin --- eeschema/qa/data/eagle_schematics/empty.sch | 88 ++-- eeschema/sch_eagle_plugin.cpp | 540 ++++++++++++++++---- eeschema/sch_eagle_plugin.h | 16 +- 3 files changed, 494 insertions(+), 150 deletions(-) diff --git a/eeschema/qa/data/eagle_schematics/empty.sch b/eeschema/qa/data/eagle_schematics/empty.sch index f452a832b6..a33e0c1b84 100644 --- a/eeschema/qa/data/eagle_schematics/empty.sch +++ b/eeschema/qa/data/eagle_schematics/empty.sch @@ -1,48 +1,48 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eeschema/sch_eagle_plugin.cpp b/eeschema/sch_eagle_plugin.cpp index 4b13fb5f6f..2ef5d5a810 100644 --- a/eeschema/sch_eagle_plugin.cpp +++ b/eeschema/sch_eagle_plugin.cpp @@ -23,18 +23,82 @@ #include #include +#include +#include #include #include +#include + using namespace std; +typedef unordered_map< string, wxXmlNode* > NodeMap; + +NodeMap mapChildren( wxXmlNode* currentNode ) +{ + // Map node_name -> node_pointer + NodeMap nodesMap; + + // Loop through all children mapping them in nodesMap + currentNode = currentNode->GetChildren(); + while( currentNode ) + { + // Create a new pair in the map + // key: current node name + // value: current node pointer + nodesMap[currentNode->GetName().ToStdString()] = currentNode; + + // Get next child + currentNode = currentNode->GetNext(); + } + + return nodesMap; +} + + +void kicadLayer( int aEagleLayer ) +{ + /** + * Layers in Kicad schematics are not actually layers, but abstract groups mainly used to + * decide item colours. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + + switch( aEagleLayer ) + { + case 90: break; + case 91: break; + case 92: break; + case 93: break; + case 94: break; + case 95: break; + case 96: break; + case 97: break; + case 98: break; + } +} + SCH_EAGLE_PLUGIN::SCH_EAGLE_PLUGIN() { m_rootSheet = nullptr; } + SCH_EAGLE_PLUGIN::~SCH_EAGLE_PLUGIN() { } @@ -61,13 +125,14 @@ int SCH_EAGLE_PLUGIN::GetModifyHash() const void SCH_EAGLE_PLUGIN::SaveLibrary( const wxString& aFileName, const PROPERTIES* aProperties ) { + } SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway, SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) { - // TODO: Handle Kiway adn uncomment next line. + // TODO: Handle Kiway and uncomment next line. // wxASSERT( !aFileName || aKiway != NULL ); // Load the document @@ -83,13 +148,11 @@ SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway, if( aAppendToMe ) { m_rootSheet = aAppendToMe->GetRootSheet(); - // deleter = make_unique( nullptr ); } else { m_rootSheet = new SCH_SHEET(); m_rootSheet->SetFileName( aFileName ); - // deleter = make_unique( m_rootSheet ); } // Retrieve the root as current node @@ -97,144 +160,385 @@ SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, KIWAY* aKiway, // If the attribute is found, store the Eagle version; // otherwise, store the dummy "0.0" version. - m_version = currentNode->GetAttribute("version", "0.0"); + m_version = currentNode->GetAttribute( "version", "0.0" ); - // Loop through all children - currentNode = currentNode->GetChildren(); - while( currentNode ) - { - wxString nodeName = currentNode->GetName(); + // Map all children into a readable dictionary + NodeMap children = mapChildren( currentNode ); - if( nodeName == "compatibility" ) - { - // TODO: handle compatibility nodes - } - else if( nodeName == "drawing") - { - loadDrawing( currentNode ); - } - else // DEFAULT - { - THROW_IO_ERROR( wxString::Format( _( "XML node '%s' unknown" ), nodeName ) ); - } + // TODO: handle compatibility nodes + // wxXmlNode* compatibility = children["compatibility"]; - currentNode = currentNode->GetNext(); - } + // Load drawing + loadDrawing( children["drawing"] ); deleter.release(); return m_rootSheet; } -void SCH_EAGLE_PLUGIN::loadDrawing( wxXmlNode* currentNode ) + +void SCH_EAGLE_PLUGIN::loadDrawing( wxXmlNode* aDrawingNode ) { - currentNode = currentNode->GetChildren(); + // Map all children into a readable dictionary + NodeMap drawingChildren = mapChildren( aDrawingNode ); + + // Board nodes should not appear in .sch files + // wxXmlNode* board = drawingChildren["board"] + + // TODO: handle grid nodes + // wxXmlNode* grid = drawingChildren["grid"] + + // TODO: handle layers nodes + // wxXmlNode* layers = drawingChildren["layers"] + + // TODO: handle library nodes + // wxXmlNode* library = drawingChildren["library"] + + // TODO: handle settings nodes + // wxXmlNode* settings = drawingChildren["settings"] + + // Load schematic + loadSchematic( drawingChildren["schematic"] ); +} + + +void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode ) +{ + // Map all children into a readable dictionary + NodeMap schematicChildren = mapChildren( aSchematicNode ); + + // TODO : handle classes nodes + // wxXmlNode* classes = schematicChildren["classes"]; + + // TODO : handle description nodes + // wxXmlNode* description = schematicChildren["description"]; + + // TODO : handle errors nodes + // wxXmlNode* errors = schematicChildren["errors"]; + + // TODO : handle modules nodes + // wxXmlNode* modules = schematicChildren["modules"]; + + // TODO : handle parts nodes + // wxXmlNode* parts = schematicChildren["parts"]; + + // TODO : handle variantdefs nodes + // wxXmlNode* variantdefs = schematicChildren["variantdefs"]; + + // TODO: handle attributes node + // wxXmlNode* attributes = schematicChildren["attributes"]; + // Possible children: constant, display, font, layer, name, ratio, rot, size, value, x, y + + // Loop through all the libraries + wxXmlNode* libraryNode = schematicChildren["libraries"]->GetChildren(); + while( libraryNode ) + { + loadLibrary( libraryNode ); + libraryNode = libraryNode->GetNext(); + } + + // Loop through all the sheets + wxXmlNode* sheetNode = schematicChildren["sheets"]->GetChildren(); + while( sheetNode ) + { + loadSheet( sheetNode ); + sheetNode = sheetNode->GetNext(); + } +} + + +void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode ) +{ + // Map all children into a readable dictionary + NodeMap sheetChildren = mapChildren( aSheetNode ); + + // Loop through all busses + // From the DTD: "Buses receive names which determine which signals they include. + // A bus is a drawing object. It does not create any electrical connections. + // These are always created by means of the nets and their names." + wxXmlNode* busNode = sheetChildren["busses"]->GetChildren(); + while( busNode ) + { + // Get the bus name + wxString busName = busNode->GetAttribute( "name" ); + + // Load segments of this bus + loadSegments( busNode ); + + // Get next bus + busNode = busNode->GetNext(); + } + + // Loop through all nets + // From the DTD: "Net is an electrical connection in a schematic." + wxXmlNode* netNode = sheetChildren["nets"]->GetChildren(); + while( netNode ) + { + // Get the net name and class + wxString netName = netNode->GetAttribute( "name" ); + wxString netClass = netNode->GetAttribute( "class" ); + + // Load segments of this net + loadSegments( netNode ); + + // Get next net + netNode = netNode->GetNext(); + } + + // Loop through all instances + wxXmlNode* instanceNode = sheetChildren["instances"]->GetChildren(); + while( instanceNode ) + { + loadInstance( instanceNode ); + instanceNode = instanceNode->GetNext(); + } + + // Loop through all moduleinsts + wxXmlNode* moduleinstNode = sheetChildren["moduleinsts"]->GetChildren(); + while( moduleinstNode ) + { + loadModuleinst( moduleinstNode ); + moduleinstNode = moduleinstNode->GetNext(); + } + + // TODO: do something with the description + // wxXmlNode* description = sheetChildren["description"]; + // wxString language = description->GetAttribute( "language", "en" ); // Defaults to "en" + // wxString description = description->GetNodeContent(); + + // TODO: do something with the plain + // wxXmlNode* plain = sheetChildren["plain"]; +} + + +void SCH_EAGLE_PLUGIN::loadSegments( wxXmlNode* aSegmentsNode ) +{ + // Loop through all segments + wxXmlNode* currentSegment = aSegmentsNode->GetChildren(); + + while( currentSegment ) + { + // Loop through all segment children + wxXmlNode* segmentAttribute = currentSegment->GetChildren(); + + while( segmentAttribute ) + { + wxString nodeName = segmentAttribute->GetName(); + + if( nodeName == "junction" ) + { + // TODO: handle junctions attributes + segmentAttribute->GetAttribute( "x" ); + segmentAttribute->GetAttribute( "y" ); + } + else if( nodeName == "label" ) + { + // TODO: handle labels attributes + segmentAttribute->GetAttribute( "x" ); // REQUIRED + segmentAttribute->GetAttribute( "y" ); // REQUIRED + segmentAttribute->GetAttribute( "size" ); // REQUIRED + segmentAttribute->GetAttribute( "layer" ); // REQUIRED + segmentAttribute->GetAttribute( "font" ); // Defaults to "proportional" + segmentAttribute->GetAttribute( "ratio" ); // Defaults to "8" + segmentAttribute->GetAttribute( "rot" ); // Defaults to "R0" + segmentAttribute->GetAttribute( "xref" ); // Defaults to "no" + } + else if( nodeName == "pinref" ) + { + // TODO: handle pinref attributes + segmentAttribute->GetAttribute( "gate" ); // REQUIRED + segmentAttribute->GetAttribute( "part" ); // REQUIRED + segmentAttribute->GetAttribute( "pin" ); // REQUIRED + } + else if( nodeName == "portref" ) + { + // TODO: handle portref attributes + segmentAttribute->GetAttribute( "moduleinst" ); // REQUIRED + segmentAttribute->GetAttribute( "port" ); // REQUIRED + } + else if( nodeName == "wire" ) + { + loadWire( segmentAttribute ); + } + else // DEFAULT + { + THROW_IO_ERROR( wxString::Format( _( "XML node '%s' unknown" ), nodeName ) ); + } + + // Get next segment attribute + segmentAttribute = segmentAttribute->GetNext(); + } + + currentSegment = currentSegment->GetNext(); + } +} + + +SCH_LINE* SCH_EAGLE_PLUGIN::loadWire( wxXmlNode* aWireNode ) +{ + std::unique_ptr< SCH_LINE > wire( new SCH_LINE ); + + wxString layer = aWireNode->GetAttribute( "layer" ); // REQUIRED + wxString width = aWireNode->GetAttribute( "width" ); // REQUIRED + wxString x1 = aWireNode->GetAttribute( "x1" ); // REQUIRED + wxString x2 = aWireNode->GetAttribute( "x2" ); // REQUIRED + wxString y1 = aWireNode->GetAttribute( "y1" ); // REQUIRED + wxString y2 = aWireNode->GetAttribute( "y2" ); // REQUIRED + wxString cap = aWireNode->GetAttribute( "cap", "round" ); // Defaults to "round" + wxString curve = aWireNode->GetAttribute( "curve", "0" ); // Defaults to "0" + wxString style = aWireNode->GetAttribute( "style", "continuous" ); // Defaults to "continuous" + // wxString extent = aWireNode->GetAttribute( "extent" ); // Non-required, defaults to NOTHING + + // TODO: layer map? + // wire->SetLayer( layerMap( layer ) ); + + // if( strCompare( "Wire", line, &line ) ) + // wire->SetLayer( LAYER_WIRE ); + // else if( strCompare( "Bus", line, &line ) ) + // wire->SetLayer( LAYER_BUS ); + // else if( strCompare( "Notes", line, &line ) ) + // wire->SetLayer( LAYER_NOTES ); + // else + // SCH_PARSE_ERROR( "invalid line type", aReader, line ); + + wxPoint begin, end; + + begin.x = wxAtoi( x1 ); + begin.y = wxAtoi( y1 ); + end.x = wxAtoi( x2 ); + end.y = wxAtoi( y2 ); + + wire->SetStartPoint( begin ); + wire->SetEndPoint( end ); + + return wire.release(); + +} + + +void SCH_EAGLE_PLUGIN::loadInstance( wxXmlNode* aInstanceNode ) +{ +} + + +void SCH_EAGLE_PLUGIN::loadModuleinst( wxXmlNode* aModuleinstNode ) +{ +} + + +void SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode ) +{ + // Read the library name + wxString libName = aLibraryNode->GetAttribute( "name" ); + + // Query all children and map them into a readable dictionary + NodeMap libraryChildren = mapChildren( aLibraryNode ); + + // TODO: Do something with the description + // wxXmlNode* libraryChildren["description"]; + + // Loop through the devicesets and load each of them + // wxXmlNode* devicesetNode = libraryChildren["devicesets"].GetChildren(); + // while( devicesetNode ) + // { + // loadDeviceset( devicesetNode ); + // devicesetNode = devicesetNode->GetNext(); + // } + + // Loop through the packages and load each of them + // wxXmlNode* packageNode = libraryChildren["packages"].GetChildren(); + // while( packageNode ) + // { + // loadPackage( packageNode ); + // packageNode = packageNode->GetNext(); + // } + + // Loop through the symbols and load each of them + wxXmlNode* symbolNode = libraryChildren["symbols"]->GetChildren(); + while( symbolNode ) + { + loadSymbol( symbolNode ); + symbolNode = symbolNode->GetNext(); + } +} + + +LIB_PART* SCH_EAGLE_PLUGIN::loadSymbol( wxXmlNode* aSymbolNode ) +{ + // Create a new part with the symbol name + wxString symbolName = aSymbolNode->GetAttribute( "name" ); + std::unique_ptr< LIB_PART > part( new LIB_PART( symbolName ) ); + + wxXmlNode* currentNode = aSymbolNode->GetChildren(); while( currentNode ) { wxString nodeName = currentNode->GetName(); - if( nodeName == "board" ) + if( nodeName == "description" ) { - // TODO: handle board nodes + // TODO: Do something with the description } - else if( nodeName == "grid" ) + else if( nodeName == "dimension" ) { - // TODO: handle grid nodes + // TODO: Handle dimension } - else if( nodeName == "layers" ) + else if( nodeName == "frame" ) { - // TODO: handle layers nodes } - else if( nodeName == "library" ) + else if( nodeName == "circle" ) { - // TODO: handle library nodes + part->AddDrawItem( loadCircle( part, currentNode ) ); } - else if( nodeName == "schematic" ) + else if( nodeName == "pin" ) { - loadSchematic( currentNode ); + part->AddDrawItem( loadPin( part, currentNode ) ); } - else if( nodeName == "settings" ) + else if( nodeName == "polygon" ) { - // TODO: handle settings nodes + part->AddDrawItem( loadPolyline( part, currentNode ) ); } - else // DEFAULT + else if( nodeName == "rectangle" ) { - THROW_IO_ERROR( wxString::Format( _( "XML node '%s' unknown" ), nodeName ) ); + part->AddDrawItem( loadRectangle( part, currentNode ) ); + } + else if( nodeName == "text" ) + { + part->AddDrawItem( loadText( part, currentNode ) ); + } + else if( nodeName == "wire" ) + { + part->AddDrawItem( loadPolyline( part, currentNode ) ); } currentNode = currentNode->GetNext(); } + + return part.release(); } -void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* currentNode ) +LIB_CIRCLE* SCH_EAGLE_PLUGIN::loadCircle( LIB_PART* aPart, wxXmlNode* aCircleNode ) { - currentNode = currentNode->GetChildren(); + unique_ptr< LIB_CIRCLE > circle( new LIB_CIRCLE( aPart.get() ) ); - while( currentNode ) - { - wxString nodeName = currentNode->GetName(); + int layer = wxAtoi( aCircleNode->GetAttribute( "layer" ) ); - if( nodeName == "attributes" ) - { - wxXmlNode* attributeNode = currentNode->GetChildren(); - while( attributeNode ) - { - // TODO: handle attributes - // Possible attributes: constant, display, font, layer, name, - // ratio, rot, size, value, x, y. - attributeNode = attributeNode->GetNext(); - } - } - else if( nodeName == "classes" ) - { - // TODO : handle classes nodes - } - else if( nodeName == "description" ) - { - // TODO : handle description nodes - } - else if( nodeName == "errors" ) - { - // TODO : handle errors nodes - } - else if( nodeName == "libraries" ) - { - // TODO : handle libraries nodes - } - else if( nodeName == "modules" ) - { - // TODO : handle modules nodes - } - else if( nodeName == "parts" ) - { - // TODO : handle parts nodes - } - else if( nodeName == "sheets" ) - { - wxXmlNode* sheetNode = currentNode->GetChildren(); - while( sheetNode ) - { - loadSheet( sheetNode ); - sheetNode = sheetNode->GetNext(); - } - } - else if( nodeName == "variantdefs" ) - { - // TODO : handle variantdefs nodes - } - else // DEFAULT - { - THROW_IO_ERROR( wxString::Format( _( "XML node '%s' unknown" ), nodeName ) ); - } + int x; + int y; + int radius; + int width; - currentNode = currentNode->GetNext(); - } + aCircleNode->GetAttribute( "x" ).ToDouble( &x ); + aCircleNode->GetAttribute( "y" ).ToDouble( &y ); + aCircleNode->GetAttribute( "radius" ).ToDouble( &radius ); + aCircleNode->GetAttribute( "width" ).ToDouble( &width ); + + circle->SetPosition( wxPoint( x, y ) ); + circle->SetRadius( radius ); + circle->SetWidth( width ; + + return circle.release(); } -void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* currentNode ) -{ - -} void SCH_EAGLE_PLUGIN::Save( const wxString& aFileName, SCH_SCREEN* aSchematic, KIWAY* aKiway, const PROPERTIES* aProperties ) @@ -299,6 +603,38 @@ bool SCH_EAGLE_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath ) return false; } + void SCH_EAGLE_PLUGIN::SymbolLibOptions( PROPERTIES* aListToAppendTo ) const { } + +// approved +// attribute +// circle +// clearance +// connect +// contactref +// description +// dimension +// frame +// gate +// grid +// hole +// junction +// label +// layer +// note +// pad +// param +// pin +// pinref +// port +// portref +// rectangle +// setting +// smd +// textvariant +// variantdef +// vertex +// via +// wire diff --git a/eeschema/sch_eagle_plugin.h b/eeschema/sch_eagle_plugin.h index 7459e59eb0..d76247fc78 100644 --- a/eeschema/sch_eagle_plugin.h +++ b/eeschema/sch_eagle_plugin.h @@ -24,6 +24,7 @@ #include +#include #include // class KIWAY; @@ -47,7 +48,7 @@ /** * Class SCH_EAGLE_PLUGIN - * is a #SCH_PLUGIN derivation for loading Autodesk Eagle schematic files. + * is a #SCH_PLUGIN derivation for loading 6.x+ Eagle schematic files. * * * As with all SCH_PLUGINs there is no UI dependencies i.e. windowing @@ -104,9 +105,16 @@ public: private: - void loadDrawing( wxXmlNode* node ); - void loadSchematic( wxXmlNode* node ); - void loadSheet( wxXmlNode* node ); + void loadDrawing( wxXmlNode* aDrawingNode ); + void loadSchematic( wxXmlNode* aSchematicNode ); + void loadSheet( wxXmlNode* aSheetNode ); + void loadSegments( wxXmlNode* aSegmentsNode ); + SCH_LINE* loadWire( wxXmlNode* aWireNode ); + void loadInstance( wxXmlNode* aInstanceNode ); + void loadModuleinst( wxXmlNode* aModuleinstNode ); + void loadLibrary( wxXmlNode* aLibraryNode ); + LIB_PART* loadSymbol( wxXmlNode* aSymbolNode ); + SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.. wxString m_version; ///< Eagle file version.