summaryrefslogtreecommitdiffstats
path: root/src/electronics/component.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/component.cpp')
-rw-r--r--src/electronics/component.cpp1017
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"
+
+