You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1018 lines
26 KiB
1018 lines
26 KiB
15 years ago
|
/***************************************************************************
|
||
|
* 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"
|
||
|
|
||
|
|