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.
ktechlab/src/electronics/ecnode.cpp

240 lines
5.7 KiB

/***************************************************************************
* Copyright (C) 2003-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 "circuitdocument.h"
#include "src/core/ktlconfig.h"
#include "component.h"
#include "connector.h"
#include "ecnode.h"
#include "pin.h"
#include <kdebug.h>
#include <tqpainter.h>
#include <cmath>
// The voltage at the middle of the voltage indicator
const double vMidPoint = 5.;
// The maximum length of the voltage indiactor
const int vLength = 8;
// The current at the middle of the current indicator
const double iMidPoint = 0.03;
// The maximum thicnkess of the current indicator
const int iLength = 6;
inline double calcVProp( const double v )
{
return 1 - vMidPoint/(vMidPoint+std::abs(v));
}
inline double calcIProp( const double i )
{
return 1 - iMidPoint/(iMidPoint+std::abs(i));
}
inline int calcThickness( const double prop )
{
return (int)((iLength-2)*prop+2);
}
inline int calcLength( const double prop, const double v )
{
return (v>0) ? -int(vLength*prop) : int(vLength*prop);
}
ECNode::ECNode( ICNDocument *icnDocument, Node::node_type _type, node_dir dir, const TQPoint &pos, TQString *_id )
: Node( icnDocument, _type, dir, pos, _id )
{
m_prevV = 0;
m_prevI = 0;
m_pinPoint = 0l;
m_bShowVoltageBars = KTLConfig::showVoltageBars();
icnDocument->registerItem(this);
if ( type() == ec_pin )
{
m_pinPoint = new TQCanvasRectangle( 0, 0, 3, 3, canvas() );
m_pinPoint->setBrush(TQt::black);
m_pinPoint->setPen(TQt::black);
}
m_pins.resize(1);
m_pins[0] = new Pin(this);
}
ECNode::~ECNode()
{
if (m_pinPoint)
m_pinPoint->setCanvas(0l);
delete m_pinPoint;
m_pinPoint = 0l;
for ( unsigned i = 0; i < m_pins.size(); i++ )
delete m_pins[i];
m_pins.resize(0);
}
void ECNode::setNumPins( unsigned num )
{
unsigned oldNum = m_pins.size();
if ( num == oldNum )
return;
if ( num > oldNum )
{
m_pins.resize(num);
for ( unsigned i = oldNum; i < num; i++ )
m_pins[i] = new Pin(this);
}
else
{
for ( unsigned i = num; i < oldNum; i++ )
delete m_pins[i];
m_pins.resize(num);
}
emit numPinsChanged(num);
}
void ECNode::setNodeChanged()
{
if ( !canvas() || numPins() != 1 )
return;
Pin * pin = m_pins[0];
double v = pin->voltage();
double i = pin->current();
if ( v != m_prevV || i != m_prevI )
{
TQRect r = boundingRect();
r.setCoords( r.left()+(r.width()/2)-1, r.top()+(r.height()/2)-1, r.right()-(r.width()/2)+1, r.bottom()-(r.height()/2)+1 );
canvas()->setChanged(r);
m_prevV = v;
m_prevI = i;
}
}
void ECNode::setParentItem( CNItem * parentItem )
{
Node::setParentItem(parentItem);
if ( Component * component = dynamic_cast<Component*>(parentItem) )
{
connect( component, TQT_SIGNAL(elementDestroyed(Element* )), this, TQT_SLOT(removeElement(Element* )) );
connect( component, TQT_SIGNAL(switchDestroyed( Switch* )), this, TQT_SLOT(removeSwitch( Switch* )) );
}
}
void ECNode::removeElement( Element * e )
{
for ( unsigned i = 0; i < m_pins.size(); i++ )
m_pins[i]->removeElement(e);
}
void ECNode::removeSwitch( Switch * sw )
{
for ( unsigned i = 0; i < m_pins.size(); i++ )
m_pins[i]->removeSwitch( sw );
}
void ECNode::drawShape( TQPainter &p )
{
const int _x = int(x());
const int _y = int(y());
if ( type() == ec_junction )
{
// p.drawRect( _x-2, _y-1, 5, 3 );
// p.drawRect( _x-1, _y-2, 3, 5 );
p.drawRect( _x-1, _y-1, 3, 3 );
return;
}
if (m_pinPoint)
{
bool drawDivPoint;
TQPoint divPoint = findConnectorDivergePoint(&drawDivPoint);
m_pinPoint->tqsetVisible(drawDivPoint);
m_pinPoint->move( divPoint.x()-1, divPoint.y()-1 );
}
// Now to draw on our current/voltage bar indicators
if ( numPins() == 1 )
{
double v = pin()->voltage();
double vProp = calcVProp(v);
int length = calcLength( vProp, v );
if ( m_bShowVoltageBars && length != 0 )
{
// we can assume that v != 0 as length != 0
TQPen oldPen = p.pen();
double i = pin()->current();
double iProp = calcIProp(i);
int thickness = calcThickness(iProp);
if ( v > 0 )
p.setPen( TQPen( TQColor( 255, 166, 0 ), thickness ) );
else
p.setPen( TQPen( TQColor( 0, 136, 255 ), thickness ) );
// The node line (drawn at the end of this function) will overdraw
// some of the voltage bar, so we need to adapt the length
if ( v > 0 && (m_dir == Node::dir_up || m_dir == Node::dir_down) )
length--;
else if ( v < 0 && (m_dir == Node::dir_left || m_dir == Node::dir_right) )
length++;
if ( m_dir == Node::dir_right )
p.drawLine( _x+3, _y, _x+3, _y+length );
else if ( m_dir == Node::dir_down )
p.drawLine( _x, _y+3, _x-length, _y+3 );
else if ( m_dir == Node::dir_left )
p.drawLine( _x-3, _y, _x-3, _y+length );
else if ( m_dir == Node::dir_up )
p.drawLine( _x, _y-3, _x-length, _y-3 );
p.setPen(oldPen);
}
}
TQPen pen( p.pen() );
pen.setWidth( (numPins() > 1) ? 2 : 1 );
p.setPen(pen);
if ( m_dir == Node::dir_right ) p.drawLine( _x, _y, _x+8, _y );
else if ( m_dir == Node::dir_down ) p.drawLine( _x, _y, _x, _y+8 );
else if ( m_dir == Node::dir_left ) p.drawLine( _x, _y, _x-8, _y );
else if ( m_dir == Node::dir_up ) p.drawLine( _x, _y, _x, _y-8 );
}
#include "ecnode.moc"