diff options
Diffstat (limited to 'src/electronics/component.cpp')
-rw-r--r-- | src/electronics/component.cpp | 1017 |
1 files changed, 1017 insertions, 0 deletions
diff --git a/src/electronics/component.cpp b/src/electronics/component.cpp new file mode 100644 index 0000000..f9f3c12 --- /dev/null +++ b/src/electronics/component.cpp @@ -0,0 +1,1017 @@ +/*************************************************************************** + * Copyright (C) 2004-2005 by David Saxton * + * david@bluehaze.org * + * * + * 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 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "canvasitemparts.h" +#include "circuitdocument.h" +#include "component.h" +#include "src/core/ktlconfig.h" +#include "ecnode.h" +#include "itemdocumentdata.h" +#include "node.h" +#include "pin.h" +#include "simulator.h" + +#include "bjt.h" +#include "capacitance.h" +#include "cccs.h" +#include "ccvs.h" +#include "currentsignal.h" +#include "currentsource.h" +#include "diode.h" +#include "inductance.h" +#include "logic.h" +#include "opamp.h" +#include "resistance.h" +#include "switch.h" +#include "vccs.h" +#include "vcvs.h" +#include "voltagepoint.h" +#include "voltagesignal.h" +#include "voltagesource.h" + +#include <cmath> +#include <kdebug.h> +#include <qbitarray.h> +#include <qpainter.h> +#include <qwidget.h> +#include <qwmatrix.h> + +const int dipWidth = 112; +const int pairSep = 32; + +// Degrees per radian +static const double DPR = 57.29577951308232087665461840231273527024; + +Component::Component( ICNDocument *icnDocument, bool newItem, const QString &id ) + : CNItem( icnDocument, newItem, id ), + m_angleDegrees(0), + b_flipped(false) +{ + m_pCircuitDocument = dynamic_cast<CircuitDocument*>(icnDocument); + + for ( int i=0; i<4; ++i ) + { + m_pPNode[i] = 0l; + m_pNNode[i] = 0l; + } + + // Get configuration options + slotUpdateConfiguration(); + + // And finally register this :-) + icnDocument->registerItem(this); +} + +Component::~Component() +{ + removeElements(); + Simulator::self()->detachComponent(this); +} + +void Component::removeItem( ) +{ + if (b_deleted) + return; + Simulator::self()->detachComponent(this); + CNItem::removeItem(); +} + +void Component::removeElements( bool setPinsInterIndependent ) +{ + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + Element * e = (*it).e; + if (e) + { + emit elementDestroyed(e); + e->componentDeleted(); + } + } + m_elementMapList.clear(); + + const SwitchList::iterator swEnd = m_switchList.end(); + for ( SwitchList::iterator it = m_switchList.begin(); it != swEnd; ++it ) + { + Switch * sw = *it; + if ( !sw ) + continue; + + emit switchDestroyed( sw ); + delete sw; + } + m_switchList.clear(); + + if ( setPinsInterIndependent ) + setAllPinsInterIndependent(); +} + + +void Component::removeElement( Element * element, bool setPinsInterIndependent ) +{ + if (!element) + return; + + emit elementDestroyed(element); + element->componentDeleted(); + + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ) + { + ElementMapList::iterator next = it; + ++next; + + if ( (*it).e == element ) + m_elementMapList.remove(it); + + it = next; + } + + if ( setPinsInterIndependent ) + rebuildPinInterDepedence(); +} + + +void Component::removeSwitch( Switch * sw ) +{ + if ( !sw ) + return; + + emit switchDestroyed( sw ); + delete sw; + m_switchList.remove(sw); + m_pCircuitDocument->requestAssignCircuits(); +} + + +void Component::setNodalCurrents() +{ + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + ElementMap m = (*it); + for ( int i=0; i<4; i++ ) + { + if ( m.n[i] ) { + m.n[i]->mergeCurrent( m.e->m_cnodeI[i] ); + } + } + } +} + + +void Component::initPainter( QPainter &p ) +{ + CNItem::initPainter(p); + + if ( !b_flipped && (m_angleDegrees%360 == 0) ) + return; + + p.save(); + + p.translate( int(x()), int(y()) ); + if (b_flipped) + p.scale( -1, 1 ); + + p.rotate(m_angleDegrees); + p.translate( -int(x()), -int(y()) ); +} + + +void Component::deinitPainter( QPainter &p ) +{ + if ( !b_flipped && (m_angleDegrees%360 == 0) ) + return; + + p.restore(); +} + + +void Component::setAngleDegrees( int degrees ) +{ + updateConnectorPoints(false); + m_angleDegrees = degrees; + itemPointsChanged(); + updateAttachedPositioning(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +void Component::setFlipped( bool flipped ) +{ + updateConnectorPoints(false); + b_flipped = flipped; + itemPointsChanged(); + updateAttachedPositioning(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +void Component::itemPointsChanged() +{ + QPointArray transformedPoints = transMatrix( m_angleDegrees, b_flipped, 0, 0, false ).map(m_itemPoints); +// transformedPoints.translate( int(x()), int(y()) ); + setPoints(transformedPoints); +} + + +void Component::restoreFromItemData( const ItemData &itemData ) +{ + CNItem::restoreFromItemData(itemData); + + setAngleDegrees( int(itemData.angleDegrees) ); + setFlipped(itemData.flipped); +} + + +ItemData Component::itemData() const +{ + ItemData itemData = CNItem::itemData(); + itemData.angleDegrees = m_angleDegrees; + itemData.flipped = b_flipped; + return itemData; +} + + +QWMatrix Component::transMatrix( int angleDegrees, bool flipped, int x, int y, bool inverse ) +{ + QWMatrix m; + m.translate( x, y ); + if (inverse) + { + m.rotate(-angleDegrees); + if (flipped) + m.scale( -1, 1 ); + } + else + { + if (flipped) + m.scale( -1, 1 ); + m.rotate(angleDegrees); + } + m.translate( -x, -y ); + m.setTransformationMode( QWMatrix::Areas ); + return m; +} + + +void Component::finishedCreation() +{ + CNItem::finishedCreation(); + updateAttachedPositioning(); +} + + +void Component::updateAttachedPositioning() +{ + if (b_deleted || !m_bDoneCreation) + return; + + //BEGIN Transform the nodes + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + if ( !it.data().node ) + kdError() << k_funcinfo << "Node in nodemap is null" << endl; + else + { + int nx = int((std::cos(m_angleDegrees/DPR) * it.data().x) - (std::sin(m_angleDegrees/DPR) * it.data().y)); + int ny = int((std::sin(m_angleDegrees/DPR) * it.data().x) + (std::cos(m_angleDegrees/DPR) * it.data().y)); + + if (b_flipped) + nx = -nx; + +#define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8) + nx = round_8(nx); + ny = round_8(ny); +#undef round_8 + + int newDir = (((m_angleDegrees + it.data().orientation)%360)+360)%360; + if (b_flipped) + newDir = (((180-newDir)%360)+360)%360; + + it.data().node->move( nx+x(), ny+y() ); + it.data().node->setOrientation( (Node::node_dir)newDir ); + } + } + //END Transform the nodes + + + //BEGIN Transform the GuiParts + QWMatrix m; + + if (b_flipped) + m.scale( -1, 1 ); + m.rotate(m_angleDegrees); + m.setTransformationMode( QWMatrix::Areas ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + QRect newPos = m.mapRect( it.data()->recommendedRect() ); + it.data()->move( newPos.x() + x(), newPos.y() + y() ); + it.data()->setGuiPartSize( newPos.width(), newPos.height() ); + it.data()->setAngleDegrees(m_angleDegrees); + } + const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); + for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) + { + QRect newPos = m.mapRect( it.data()->recommendedRect() ); + it.data()->move( newPos.x() + x(), newPos.y() + y() ); + it.data()->setGuiPartSize( newPos.width(), newPos.height() ); + it.data()->setAngleDegrees(m_angleDegrees); + } + //END Transform the GuiParts +} + + +void Component::drawPortShape( QPainter & p ) +{ + int h = height(); + int w = width() - 1; + int _x = int( x() + offsetX() ); + int _y = int( y() + offsetY() ); + + double roundSize = 8; + double slantIndent = 8; + + const double pi = 3.1415926536; + const double DPR = 180./pi; + double inner = std::atan(h/slantIndent); // Angle for slight corner + double outer = pi-inner; // Angle for sharp corner + + int inner16 = int(16*inner*DPR); + int outer16 = int(16*outer*DPR); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawPolygon( areaPoints() ); + p.restore(); + + initPainter( p ); + + // Left line + p.drawLine( int(_x), int(_y+roundSize/2), int(_x), int(_y+h-roundSize/2) ); + + // Right line + p.drawLine( int(_x+w), int(_y-slantIndent+h-roundSize/2), int(_x+w), int(_y+slantIndent+roundSize/2) ); + + // Bottom line + p.drawLine( int(_x+(1-std::cos(outer))*(roundSize/2)), int(_y+h+(std::sin(outer)-1)*(roundSize/2)), + int(_x+w+(std::cos(inner)-1)*(roundSize/2)), int(_y+h-slantIndent+(std::sin(inner)-1)*(roundSize/2)) ); + + // Top line + p.drawLine( int(_x+w+(std::cos(outer)-1)*(roundSize/2)), int(_y+slantIndent+(1-std::sin(inner))*(roundSize/2)), + int(_x+(1-std::cos(inner))*(roundSize/2)), int(_y+(1-std::sin(outer))*(roundSize/2)) ); + + + // Top left + p.drawArc( int(_x), int(_y), int(roundSize), int(roundSize), 90*16, outer16 ); + + // Bottom left + p.drawArc( int(_x), int(_y+h-roundSize), int(roundSize), int(roundSize), 180*16, outer16 ); + + // Top right + p.drawArc( int(_x+w-roundSize), int(_y+slantIndent), int(roundSize), int(roundSize), 0, inner16 ); + + // Bottom right + p.drawArc( int(_x+w-roundSize), int(_y-slantIndent+h-roundSize), int(roundSize), int(roundSize), 270*16, inner16 ); + + deinitPainter( p ); +} + + +void Component::initDIP( const QStringList & pins ) +{ + const int numPins = pins.size(); + const int numSide = numPins/2 + numPins%2; + + // Pins along left + for ( int i=0; i<numSide; i++ ) + { + if ( !pins[i].isEmpty() ) + { + const int nodeX = -8+offsetX(); + const int nodeY = (i+1)*16+offsetY(); + ECNode *node = ecNodeWithID(pins[i]); + if (node) + { + m_nodeMap[pins[i]].x = nodeX; + m_nodeMap[pins[i]].y = nodeY; + m_nodeMap[pins[i]].orientation = (Node::node_dir)0; + } + else + createPin( nodeX, nodeY, 0, pins[i] ); + } + } + // Pins along right + for ( int i=numSide; i<numPins; i++ ) + { + if ( !pins[i].isEmpty() ) + { + const int nodeX = width()+8+offsetX(); + const int nodeY = (2*numSide-i)*16+offsetY(); + ECNode *node = ecNodeWithID(pins[i]); + if (node) + { + m_nodeMap[pins[i]].x = nodeX; + m_nodeMap[pins[i]].y = nodeY; + m_nodeMap[pins[i]].orientation = (Node::node_dir)180; + } + else + createPin( nodeX, nodeY, 180, pins[i] ); + } + } + + updateAttachedPositioning(); +} + +void Component::initDIPSymbol( const QStringList & pins, int _width ) +{ + const int numPins = pins.size(); + const int numSide = numPins/2 + numPins%2; + + setSize( -(_width-(_width%16))/2, -(numSide+1)*8, _width, (numSide+1)*16, true ); + + QWidget tmpWidget; + QPainter p(&tmpWidget); + + p.setFont(m_font); + + // Pins along left + for ( int i=0; i<numSide; i++ ) + { + if ( !pins[i].isEmpty() ) + { + const QString text = *pins.at(i); + + const int _top = (i+1)*16-8 + offsetY(); + const int _width = width()/2 - 6; + const int _left = 6 + offsetX(); + const int _height = 16; + + QRect br = p.boundingRect( QRect( _left, _top, _width, _height ), Qt::AlignLeft, text ); + addDisplayText( text, br, text ); + } + } + // Pins along right + for ( int i=numSide; i<numPins; i++ ) + { + if ( !pins[i].isEmpty() ) + { + const QString text = *pins.at(i); + + const int _top = (2*numSide-i)*16 - 8 + offsetY(); + const int _width = width()/2 - 6; + const int _left = (width()/2) + offsetX(); + const int _height = 16; + + QRect br = p.boundingRect( QRect( _left, _top, _width, _height ), Qt::AlignRight, text ); + addDisplayText( text, br, text ); + } + } + + updateAttachedPositioning(); +} + + +// QString createNode( double _x, double _y, int shape, int orientation, const QString &name, int type, bool isInput = true ); + +void Component::init1PinLeft( int h1 ) +{ + if ( h1 == -1 ) h1 = offsetY()+height()/2; + + m_pNNode[0] = createPin( offsetX()-8, h1, 0, "n1" ); +} + +void Component::init2PinLeft( int h1, int h2 ) +{ + if ( h1 == -1 ) h1 = offsetY()+8; + if ( h2 == -1 ) h2 = offsetY()+height()-8; + + m_pNNode[0] = createPin( offsetX()-8, h1, 0, "n1" ); + m_pNNode[1] = createPin( offsetX()-8, h2, 0, "n2" ); +} + +void Component::init3PinLeft( int h1, int h2, int h3 ) +{ + if ( h1 == -1 ) h1 = offsetY()+8; + if ( h2 == -1 ) h2 = offsetY()+height()/2; + if ( h3 == -1 ) h3 = offsetY()+height()-8; + + m_pNNode[0] = createPin( offsetX()-8, h1, 0, "n1" ); + m_pNNode[1] = createPin( offsetX()-8, h2, 0, "n2" ); + m_pNNode[2] = createPin( offsetX()-8, h3, 0, "n3" ); +} + +void Component::init4PinLeft( int h1, int h2, int h3, int h4 ) +{ + if ( h1 == -1 ) h1 = offsetY()+8; + if ( h2 == -1 ) h2 = offsetY()+24; + if ( h3 == -1 ) h3 = offsetY()+height()-24; + if ( h4 == -1 ) h4 = offsetY()+height()-8; + + m_pNNode[0] = createPin( offsetX()-8, h1, 0, "n1" ); + m_pNNode[1] = createPin( offsetX()-8, h2, 0, "n2" ); + m_pNNode[2] = createPin( offsetX()-8, h3, 0, "n3" ); + m_pNNode[3] = createPin( offsetX()-8, h4, 0, "n4" ); +} + +void Component::init1PinRight( int h1 ) +{ + if ( h1 == -1 ) h1 = offsetY()+height()/2; + + m_pPNode[0] = createPin( offsetX()+width()+8, h1, 180, "p1" ); +} + + +void Component::init2PinRight( int h1, int h2 ) +{ + if ( h1 == -1 ) h1 = offsetY()+8; + if ( h2 == -1 ) h2 = offsetY()+height()-8; + + m_pPNode[0] = createPin( offsetX()+width()+8, h1, 180, "p1" ); + m_pPNode[1] = createPin( offsetX()+width()+8, h2, 180, "p2" ); +} + +void Component::init3PinRight( int h1, int h2, int h3 ) +{ + if ( h1 == -1 ) h1 = offsetY()+8; + if ( h2 == -1 ) h2 = offsetY()+height()/2; + if ( h3 == -1 ) h3 = offsetY()+height()-8; + + m_pPNode[0] = createPin( offsetX()+width()+8, h1, 180, "p1" ); + m_pPNode[1] = createPin( offsetX()+width()+8, h2, 180, "p2" ); + m_pPNode[2] = createPin( offsetX()+width()+8, h3, 180, "p3" ); +} + +void Component::init4PinRight( int h1, int h2, int h3, int h4 ) +{ + if ( h1 == -1 ) h1 = offsetY()+8; + if ( h2 == -1 ) h2 = offsetY()+24; + if ( h3 == -1 ) h3 = offsetY()+height()-24; + if ( h4 == -1 ) h4 = offsetY()+height()-8; + + m_pPNode[0] = createPin( offsetX()+width()+8, h1, 180, "p1" ); + m_pPNode[1] = createPin( offsetX()+width()+8, h2, 180, "p2" ); + m_pPNode[2] = createPin( offsetX()+width()+8, h3, 180, "p3" ); + m_pPNode[3] = createPin( offsetX()+width()+8, h4, 180, "p4" ); +} + + +ECNode* Component::ecNodeWithID( const QString &ecNodeId ) +{ + return dynamic_cast<ECNode*>( p_icnDocument->nodeWithID( nodeId(ecNodeId) ) ); +} + + +void Component::slotUpdateConfiguration() +{ + const LogicConfig logicConfig = LogicIn::getConfig(); + + const ElementMapList::iterator end = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + if ( LogicIn * logicIn = dynamic_cast<LogicIn*>((*it).e) ) + logicIn->setLogic(logicConfig); + } +} + + + +BJT * Component::createBJT( ECNode *c, ECNode *b, ECNode *e, bool isNPN ) +{ return createBJT( c->pin(), b->pin(), e->pin(), isNPN ); } +Capacitance * Component::createCapacitance( ECNode *n0, ECNode *n1, double capacitance ) +{ return createCapacitance( n0->pin(), n1->pin(), capacitance ); } +CCCS * Component::createCCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createCCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +CCVS * Component::createCCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createCCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +CurrentSignal * Component::createCurrentSignal( ECNode *n0, ECNode *n1, double current ) +{ return createCurrentSignal( n0->pin(), n1->pin(), current ); } +CurrentSource * Component::createCurrentSource( ECNode *n0, ECNode *n1, double current ) +{ return createCurrentSource( n0->pin(), n1->pin(), current ); } +Diode * Component::createDiode( ECNode *n0, ECNode *n1 ) +{ return createDiode( n0->pin(), n1->pin() ); } +Inductance * Component::createInductance( ECNode *n0, ECNode *n1, double inductance ) +{ return createInductance( n0->pin(), n1->pin(), inductance ); } +LogicIn * Component::createLogicIn( ECNode *node ) +{ return createLogicIn( node->pin() ); } +LogicOut * Component::createLogicOut( ECNode *node, bool isHigh ) +{ return createLogicOut( node->pin(), isHigh ); } +OpAmp * Component::createOpAmp( ECNode * nonInverting, ECNode * out, ECNode * inverting ) +{ return createOpAmp( nonInverting->pin(), out->pin(), inverting->pin() ); } +Resistance * Component::createResistance( ECNode *n0, ECNode *n1, double resistance ) +{ return createResistance( n0->pin(), n1->pin(), resistance ); } +Switch * Component::createSwitch( ECNode *n0, ECNode *n1, bool open ) +{ return createSwitch( n0->pin(), n1->pin(), open ); } +VCCS * Component::createVCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createVCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +VCVS * Component::createVCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) +{ return createVCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } +VoltagePoint * Component::createVoltagePoint( ECNode *n0, double voltage ) +{ return createVoltagePoint( n0->pin(), voltage ); } +VoltageSignal * Component::createVoltageSignal( ECNode *n0, ECNode *n1, double voltage ) +{ return createVoltageSignal( n0->pin(), n1->pin(), voltage ); } +VoltageSource * Component::createVoltageSource( ECNode *n0, ECNode *n1, double voltage ) +{ return createVoltageSource( n0->pin(), n1->pin(), voltage ); } + +BJT* Component::createBJT( Pin *cN, Pin *bN, Pin *eN, bool isNPN ) +{ + BJT *e = new BJT(isNPN); + + QValueList<Pin*> pins; + pins << bN << cN << eN; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Capacitance* Component::createCapacitance( Pin *n0, Pin *n1, double capacitance ) +{ + Capacitance *e = new Capacitance( capacitance, 1./LINEAR_UPDATE_RATE ); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CCCS* Component::createCCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + CCCS *e = new CCCS(gain); + + QValueList<Pin*> pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CCVS* Component::createCCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + CCVS *e = new CCVS(gain); + + QValueList<Pin*> pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterCircuitDependent( it, pins ); + + pins.clear(); + pins << n0 << n1; + setInterGroundDependent( it, pins ); + + pins.clear(); + pins << n2 << n3; + setInterGroundDependent( it, pins ); + + return e; +} + +CurrentSignal* Component::createCurrentSignal( Pin *n0, Pin *n1, double current ) +{ + CurrentSignal *e = new CurrentSignal( 1./LINEAR_UPDATE_RATE, current ); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +CurrentSource* Component::createCurrentSource( Pin *n0, Pin *n1, double current ) +{ + CurrentSource *e = new CurrentSource(current); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Diode* Component::createDiode( Pin *n0, Pin *n1 ) +{ + Diode *e = new Diode(); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Inductance* Component::createInductance( Pin *n0, Pin *n1, double inductance ) +{ + Inductance *e = new Inductance( inductance, 1./LINEAR_UPDATE_RATE ); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +LogicIn *Component::createLogicIn( Pin *node ) +{ + LogicIn *e = new LogicIn(LogicIn::getConfig()); + + QValueList<Pin*> pins; + pins << node; + + ElementMapList::iterator it = handleElement( e, pins ); + return e; +} + +LogicOut *Component::createLogicOut( Pin *node, bool isHigh ) +{ + LogicOut *e = new LogicOut( LogicIn::getConfig(), isHigh); + + QValueList<Pin*> pins; + pins << node; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +OpAmp * Component::createOpAmp( Pin * nonInverting, Pin * inverting, Pin * out ) +{ + OpAmp * e = new OpAmp(); + + QValueList<Pin*> pins; + pins << nonInverting << inverting << out; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Resistance* Component::createResistance( Pin *n0, Pin *n1, double resistance ) +{ + Resistance *e = new Resistance(resistance); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +Switch* Component::createSwitch( Pin *n0, Pin *n1, bool open ) +{ + // Note that a Switch is not really an element (although in many cases it + // behaves very much like one). + + Switch * e = new Switch( this, n0, n1, open ? Switch::Open : Switch::Closed ); + m_switchList.append(e); + n0->addSwitch( e ); + n1->addSwitch( e ); + emit switchCreated( e ); + return e; +} + +VCCS* Component::createVCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + VCCS *e = new VCCS(gain); + + QValueList<Pin*> pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VCVS* Component::createVCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) +{ + VCVS *e = new VCVS(gain); + + QValueList<Pin*> pins; + pins << n0 << n1 << n2 << n3; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterCircuitDependent( it, pins ); + + pins.clear(); + pins << n0 << n1; + setInterGroundDependent( it, pins ); + + pins.clear(); + pins << n2 << n3; + setInterGroundDependent( it, pins ); + return e; +} + +VoltagePoint* Component::createVoltagePoint( Pin *n0, double voltage ) +{ + VoltagePoint *e = new VoltagePoint(voltage); + + QValueList<Pin*> pins; + pins << n0; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VoltageSignal* Component::createVoltageSignal( Pin *n0, Pin *n1, double voltage ) +{ + VoltageSignal *e = new VoltageSignal( 1./LINEAR_UPDATE_RATE, voltage ); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + +VoltageSource* Component::createVoltageSource( Pin *n0, Pin *n1, double voltage ) +{ + VoltageSource *e = new VoltageSource(voltage); + + QValueList<Pin*> pins; + pins << n0 << n1; + + ElementMapList::iterator it = handleElement( e, pins ); + setInterDependent( it, pins ); + return e; +} + + +ElementMapList::iterator Component::handleElement( Element *e, const QValueList<Pin*> & pins ) +{ + if (!e) + return m_elementMapList.end(); + + ElementMap em; + em.e = e; + int at = 0; + QValueList<Pin*>::ConstIterator end = pins.end(); + for ( QValueList<Pin*>::ConstIterator it = pins.begin(); it != end; ++it ) + { + (*it)->addElement(e); + em.n[at++] = *it; + } + + ElementMapList::iterator it = m_elementMapList.append(em); + + emit elementCreated(e); + return it; +} + + +void Component::setInterDependent( ElementMapList::iterator it, const QValueList<Pin*> & pins ) +{ + setInterCircuitDependent( it, pins ); + setInterGroundDependent( it, pins ); +} + + +void Component::setInterCircuitDependent( ElementMapList::iterator it, const QValueList<Pin*> & pins ) +{ + QValueList<Pin*>::ConstIterator end = pins.end(); + for ( QValueList<Pin*>::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) + { + for ( QValueList<Pin*>::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) + { + (*it1)->addCircuitDependentPin( *it2 ); + } + } + + (*it).interCircuitDependent.append( pins ); +} + + +void Component::setInterGroundDependent( ElementMapList::iterator it, const QValueList<Pin*> & pins ) +{ + QValueList<Pin*>::ConstIterator end = pins.end(); + for ( QValueList<Pin*>::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) + { + for ( QValueList<Pin*>::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) + { + (*it1)->addGroundDependentPin( *it2 ); + } + } + + (*it).interGroundDependent.append( pins ); +} + + +void Component::rebuildPinInterDepedence() +{ + setAllPinsInterIndependent(); + + // Rebuild dependencies + ElementMapList::iterator emlEnd = m_elementMapList.end(); + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != emlEnd; ++it ) + { + // Many copies of the pin lists as these will be affected when we call setInter*Dependent + PinListList list = (*it).interCircuitDependent; + + PinListList::iterator depEnd = list.end(); + for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) + setInterCircuitDependent( it, *depIt ); + + list = (*it).interGroundDependent; + + depEnd = list.end(); + for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) + setInterGroundDependent( it, *depIt ); + } +} + + +void Component::setAllPinsInterIndependent() +{ + NodeMap::iterator nmEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nmEnd; ++it ) + { + PinVector pins = (static_cast<ECNode*>(it.data().node))->pins(); + PinVector::iterator pinsEnd = pins.end(); + for ( PinVector::iterator pinsIt = pins.begin(); pinsIt != pinsEnd; ++pinsIt ) + { + if ( *pinsIt ) + (*pinsIt)->removeDependentPins(); + } + } +} + + +void Component::initElements( const uint stage ) +{ + /// @todo this function is ugly and messy and needs tidying up + + const ElementMapList::iterator end = m_elementMapList.end(); + + if ( stage == 1 ) + { + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + (*it).e->add_initial_dc(); + } + return; + } + + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + ElementMap m = (*it); + + if ( m.n[3] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId(), m.n[3]->eqId() ); + } + else if ( m.n[2] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId() ); + } + else if ( m.n[1] ) { + m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId() ); + } + else if ( m.n[0] ) { + m.e->setCNodes( m.n[0]->eqId() ); + } + } + + for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) + { + (*it).e->add_map(); + } +} + + +ECNode * Component::createPin( double x, double y, int orientation, const QString & name ) +{ + return dynamic_cast<ECNode*>( createNode( x, y, orientation, name, Node::ec_pin ) ); +} + + +//BEGIN class ElementMap +ElementMap::ElementMap() +{ + e = 0; + for ( int i = 0; i < 4; ++i ) + n[i] = 0; +} +//END class ElementMap + + +#include "component.moc" + + |