diff --git a/eeschema/sch_eagle_plugin.cpp b/eeschema/sch_eagle_plugin.cpp index f66fc30606..d6f54ee013 100644 --- a/eeschema/sch_eagle_plugin.cpp +++ b/eeschema/sch_eagle_plugin.cpp @@ -107,6 +107,13 @@ static EDA_RECT getSheetBbox( SCH_SHEET* aSheet ) } +///> Extracts the net name part from a pin name (e.g. return 'GND' for pin named 'GND@2') +static inline wxString extractNetName( const wxString& aPinName ) +{ + return aPinName.BeforeFirst( '@' ); +} + + wxString SCH_EAGLE_PLUGIN::getLibName() { if( m_libName.IsEmpty() ) @@ -590,6 +597,57 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode ) sheetNode = sheetNode->GetNext(); } } + + + // Handle the missing component units that need to be instantiated + // to create the missing implicit connections + + // Calculate the already placed items bounding box and the page size to determine + // placement for the new components + wxSize pageSizeIU = m_rootSheet->GetScreen()->GetPageSettings().GetSizeIU(); + EDA_RECT sheetBbox = getSheetBbox( m_rootSheet ); + wxPoint newCmpPosition( sheetBbox.GetLeft(), sheetBbox.GetBottom() ); + int maxY = sheetBbox.GetY(); + + SCH_SHEET_PATH sheetpath; + m_rootSheet->LocatePathOfScreen( m_rootSheet->GetScreen(), &sheetpath ); + + for( auto& cmp : m_missingCmps ) + { + const SCH_COMPONENT* origCmp = cmp.second.cmp; + + for( auto unitEntry : cmp.second.units ) + { + if( unitEntry.second == false ) + continue; // unit has been already processed + + // Instantiate the missing component unit + int unit = unitEntry.first; + const wxString& reference = origCmp->GetField( REFERENCE )->GetText(); + std::unique_ptr component( new SCH_COMPONENT( *origCmp ) ); + component->SetUnitSelection( &sheetpath, unit ); + component->SetUnit( unit ); + component->SetTimeStamp( EagleModuleTstamp( reference, origCmp->GetField( VALUE )->GetText(), unit ) ); + component->SetOrientation( 0 ); + component->AddHierarchicalReference( sheetpath.Path(), reference, unit ); + + // Calculate the placement position + EDA_RECT cmpBbox = component->GetBoundingBox(); + int posY = newCmpPosition.y + cmpBbox.GetHeight(); + component->SetPosition( wxPoint( newCmpPosition.x, posY ) ); + newCmpPosition.x += cmpBbox.GetWidth(); + maxY = std::max( maxY, posY ); + + if( newCmpPosition.x >= pageSizeIU.GetWidth() ) // reached the page boundary? + newCmpPosition = wxPoint( sheetBbox.GetLeft(), maxY ); // then start a new row + + // Add the global net labels to recreate the implicit connections + addImplicitConnections( component.get(), m_rootSheet->GetScreen(), false ); + m_rootSheet->GetScreen()->Append( component.release() ); + } + } + + m_missingCmps.clear(); } @@ -735,6 +793,15 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex ) item->SetPosition( item->GetPosition() + translation ); item->ClearFlags(); } + + // Add global net labels for the named power input pins in this sheet + for( SCH_ITEM* item = m_currentSheet->GetScreen()->GetDrawItems(); item; item = item->Next() ) + { + if( item->Type() != SCH_COMPONENT_T ) + continue; + + addImplicitConnections( static_cast( item ), m_currentSheet->GetScreen(), true ); + } } @@ -2400,3 +2467,71 @@ const SEG* SCH_EAGLE_PLUGIN::SEG_DESC::LabelAttached( const SCH_TEXT* aLabel ) c return nullptr; } + + +void SCH_EAGLE_PLUGIN::addImplicitConnections( SCH_COMPONENT* aComponent, + SCH_SCREEN* aScreen, bool aUpdateSet ) +{ + auto& schLibTable = *m_kiway->Prj().SchSymbolLibTable(); + wxCHECK( aComponent->Resolve( schLibTable ), /*void*/ ); + aComponent->UpdatePinCache(); + auto partRef = aComponent->GetPartRef().lock(); + wxCHECK( partRef, /*void*/ ); + + // Normally power parts also have power input pins, + // but they already force net names on the attached wires + if( partRef->IsPower() ) + return; + + int unit = aComponent->GetUnit(); + const wxString& reference = aComponent->GetField( REFERENCE )->GetText(); + std::vector pins; + partRef->GetPins( pins ); + std::set missingUnits; + + // Search all units for pins creating implicit connections + for( const auto& pin : pins ) + { + if( pin->GetType() == PIN_POWER_IN ) + { + if( !unit || pin->GetUnit() == unit ) + { + // Create a net label to force the net name on the pin + SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL; + netLabel->SetPosition( aComponent->GetPinPhysicalPosition( pin ) ); + netLabel->SetText( extractNetName( pin->GetName() ) ); + netLabel->SetTextSize( wxSize( 10, 10 ) ); + netLabel->SetLabelSpinStyle( 0 ); + aScreen->Append( netLabel ); + } + + else if( aUpdateSet ) + { + // Found a pin creating implicit connection information in another unit. + // Such units will be instantiated if they do not appear in another sheet and + // processed later. + wxASSERT( pin->GetUnit() ); + missingUnits.insert( pin->GetUnit() ); + } + } + } + + if( aUpdateSet ) + { + auto cmpIt = m_missingCmps.find( reference ); + + // Set the flag indicating this unit has been processed + if( cmpIt != m_missingCmps.end() ) + cmpIt->second.units[unit] = false; + + // Save the units that need later processing + else if( !missingUnits.empty() ) + { + EAGLE_MISSING_CMP& entry = m_missingCmps[reference]; + entry.cmp = aComponent; + + for( int i : missingUnits ) + entry.units.emplace( i, true ); + } + } +} diff --git a/eeschema/sch_eagle_plugin.h b/eeschema/sch_eagle_plugin.h index 5397e640c1..2227a8bdf6 100644 --- a/eeschema/sch_eagle_plugin.h +++ b/eeschema/sch_eagle_plugin.h @@ -208,6 +208,43 @@ private: ///> Segments representing wires for intersection checking std::vector m_segments; + + + // Structure describing missing units containing pins creating implicit connections + // (named power pins in Eagle). + struct EAGLE_MISSING_CMP + { + EAGLE_MISSING_CMP( const SCH_COMPONENT* aComponent = nullptr ) + : cmp( aComponent ) + { + } + + ///> Link to the parent component + const SCH_COMPONENT* cmp; + + /* Map of the component units: for each unit there is a flag saying + * whether the unit needs to be instantiated with appropriate net labels to + * emulate implicit connections as is done in Eagle. + */ + std::map units; + }; + + ///> Map references to missing component units data + std::map m_missingCmps; + + /** + * Creates net labels to emulate implicit connections in Eagle. + * + * Each named power input pin creates an implicit connection in Eagle. To emulate this behavior + * one needs to attach global net labels to the mentioned pins. This is is also expected for the + * units that are not instantiated in the schematics, therefore such units need to be stored + * in order to create them at later stage. + * + * @param aComponent is the component to process. + * @param aScreen is the screen where net labels should be added. + * @param aUpdateSet decides whether the missing units data should be updated. + */ + void addImplicitConnections( SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen, bool aUpdateSet ); }; #endif // _SCH_EAGLE_PLUGIN_H_