ecnode.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003-2005 by David Saxton                               *
00003  *   david@bluehaze.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include "circuitdocument.h"
00012 #include "src/core/ktlconfig.h"
00013 #include "component.h"
00014 #include "connector.h"
00015 #include "ecnode.h"
00016 #include "pin.h"
00017 
00018 #include <kdebug.h>
00019 #include <qpainter.h>
00020 
00021 #include <cmath>
00022 
00023 // The voltage at the middle of the voltage indicator
00024 const double vMidPoint = 5.;
00025 
00026 // The maximum length of the voltage indiactor
00027 const int vLength = 10;
00028 
00029 // The current at the middle of the current indicator
00030 const double iMidPoint = 0.05;
00031 
00032 // The maximum thicnkess of the current indicator
00033 const int iLength = 6;
00034 
00035 inline double calcVProp( const double v )
00036 {
00037         return 1 - vMidPoint/(vMidPoint+std::abs(v));
00038 }
00039 
00040 inline double calcIProp( const double i )
00041 {
00042         return 1 - iMidPoint/(iMidPoint+std::abs(i));
00043 }
00044 
00045 inline int calcThickness( const double prop )
00046 {
00047         return (int)((iLength-2)*prop+2);
00048 }
00049 
00050 inline int calcLength( const double prop, const double v )
00051 { 
00052         return (v>0) ? -int(vLength*prop) : int(vLength*prop);
00053 }
00054  
00055 ECNode::ECNode( ICNDocument *icnDocument, Node::node_type _type, node_dir dir, const QPoint &pos, QString *_id )
00056         : Node( icnDocument, _type, dir, pos, _id )
00057 {
00058         m_prevV = 0;
00059         m_prevI = 0;
00060         m_pinPoint = 0;
00061         m_bShowVoltageBars = KTLConfig::showVoltageBars();
00062 
00063         icnDocument->registerItem(this);
00064 
00065         if ( type() == ec_pin ) {
00066                 m_pinPoint = new QCanvasRectangle( 0, 0, 3, 3, canvas() );
00067                 m_pinPoint->setBrush(Qt::black);
00068                 m_pinPoint->setPen(Qt::black);
00069         }
00070         
00071         m_pins.resize(1);
00072         m_pins[0] = new Pin(this);
00073 }
00074 
00075 
00076 ECNode::~ECNode()
00077 {
00078         if (m_pinPoint) m_pinPoint->setCanvas(0);
00079         delete m_pinPoint;
00080 
00081         for(unsigned i = 0; i < m_pins.size(); i++)
00082                 delete m_pins[i];
00083 
00084         m_pins.resize(0);
00085 }
00086 
00087 
00088 void ECNode::setNumPins( unsigned num )
00089 {
00090         unsigned oldNum = m_pins.size();
00091 
00092         if ( num == oldNum ) return;
00093         
00094         if ( num > oldNum ) {
00095                 m_pins.resize(num);
00096                 for ( unsigned i = oldNum; i < num; i++ )
00097                         m_pins[i] = new Pin(this);
00098         } else {
00099                 for ( unsigned i = num; i < oldNum; i++ )
00100                         delete m_pins[i];
00101                 m_pins.resize(num);
00102         }
00103 
00104         emit numPinsChanged(num);
00105 }
00106 
00107 void ECNode::setNodeChanged()
00108 {
00109         if ( !canvas() || numPins() != 1 ) return;
00110 
00111         Pin * pin = m_pins[0];
00112 
00113         double v = pin->voltage();
00114         double i = pin->current();
00115 
00116         if ( v != m_prevV || i != m_prevI ) {
00117                 QRect r = boundingRect();
00118                 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 );
00119                 canvas()->setChanged(r);
00120                 m_prevV = v;
00121                 m_prevI = i;
00122         }
00123 }
00124 
00125 void ECNode::setParentItem( CNItem * parentItem )
00126 {
00127         Node::setParentItem(parentItem);
00128         
00129         if ( Component * component = dynamic_cast<Component*>(parentItem) )
00130         {
00131                 connect( component, SIGNAL(elementDestroyed(Element* )), this, SLOT(removeElement(Element* )) );
00132                 connect( component, SIGNAL(switchDestroyed( Switch* )), this, SLOT(removeSwitch( Switch* )) );
00133         }
00134 }
00135 
00136 void ECNode::removeElement( Element * e )
00137 {
00138         for ( unsigned i = 0; i < m_pins.size(); i++ )
00139                 m_pins[i]->removeElement(e);
00140 }
00141 
00142 void ECNode::removeSwitch( Switch * sw )
00143 {
00144         for ( unsigned i = 0; i < m_pins.size(); i++ )
00145                 m_pins[i]->removeSwitch( sw );
00146 }
00147 
00148 void ECNode::drawShape( QPainter &p )
00149 {
00150         const int _x = int(x());
00151         const int _y = int(y());
00152 
00153         if ( type() == ec_junction ) {
00154 //              p.drawRect( _x-2, _y-1, 5, 3 );
00155 //              p.drawRect( _x-1, _y-2, 3, 5 );
00156                 p.drawRect( _x-1, _y-1, 3, 3 );
00157                 return;
00158         }
00159         
00160         if (m_pinPoint) {
00161                 bool drawDivPoint;
00162                 QPoint divPoint = findConnectorDivergePoint(&drawDivPoint);
00163                 m_pinPoint->setVisible(drawDivPoint);
00164                 m_pinPoint->move( divPoint.x()-1, divPoint.y()-1 );
00165         }
00166         
00167         // Now to draw on our current/voltage bar indicators
00168         
00169         if ( numPins() == 1 )
00170         {
00171                 double v = pin()->voltage();
00172                 double vProp = calcVProp(v);
00173                 int length = calcLength( vProp, v );
00174         
00175                 if ( m_bShowVoltageBars && length != 0 )
00176                 {
00177                 // we can assume that v != 0 as length != 0
00178 
00179                         QPen oldPen = p.pen();
00180 
00181                         double i = pin()->current();
00182                         double iProp = calcIProp(i);
00183                         int thickness = calcThickness(iProp);
00184         
00185                         if ( v > 0 )
00186                                 p.setPen( QPen( QColor( 255, 166, 0 ), thickness ));
00187                         else p.setPen( QPen( QColor( 0, 136, 255 ), thickness ) );
00188                 
00189                         // The node line (drawn at the end of this function) will overdraw
00190                         // some of the voltage bar, so we need to adapt the length
00191                         if ( v > 0 && (m_dir == Node::dir_up || m_dir == Node::dir_down) )
00192                                 length--;
00193                         else if ( v < 0 && (m_dir == Node::dir_left || m_dir == Node::dir_right) )
00194                                 length++;
00195 
00196                         if ( m_dir == Node::dir_right )
00197                                 p.drawLine( _x+3, _y, _x+3, _y+length );
00198 
00199                         else if ( m_dir == Node::dir_down )
00200                                 p.drawLine( _x, _y+3, _x-length, _y+3 );
00201 
00202                         else if ( m_dir == Node::dir_left )
00203                                 p.drawLine( _x-3, _y, _x-3, _y+length );
00204 
00205                         else if ( m_dir == Node::dir_up )
00206                                 p.drawLine( _x, _y-3, _x-length, _y-3 );
00207 
00208                         p.setPen(oldPen);
00209                 }
00210         }
00211 
00212         QPen pen( p.pen() );
00213         pen.setWidth( (numPins() > 1) ? 2 : 1 );
00214         p.setPen(pen);
00215 
00216         if( m_dir == Node::dir_right )  p.drawLine( _x, _y, _x+8, _y );
00217         else if ( m_dir == Node::dir_down ) p.drawLine( _x, _y, _x, _y+8 );
00218         else if ( m_dir == Node::dir_left ) p.drawLine( _x, _y, _x-8, _y );
00219         else if ( m_dir == Node::dir_up )   p.drawLine( _x, _y, _x, _y-8 );
00220 }
00221 
00222 #include "ecnode.moc"
00223 

Generated on Tue May 8 17:05:29 2007 for KTechLab by  doxygen 1.5.1