meter.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 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 "canvasitemparts.h"
00012 #include "ecnode.h"
00013 #include "element.h"
00014 #include "libraryitem.h"
00015 #include "meter.h"
00016 #include "variant.h"
00017 #include "voltagesource.h"
00018 #include "pin.h"
00019 #include "simulator.h"
00020 
00021 #include <cmath>
00022 #include <klocale.h>
00023 #include <qpainter.h>
00024 
00025 
00026 //BEGIN class Meter
00027 Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id )
00028         : Component( icnDocument, newItem, id )
00029 {
00030         m_bDynamicContent = true;
00031         b_timerStarted = false;
00032         m_timeSinceUpdate = 0.;
00033         m_old_value  = 0.;
00034         m_avgValue = 0.;
00035         b_firstRun = true;
00036         setSize( -16, -16, 32, 32 );
00037 
00038         p_displayText = addDisplayText( "meter", QRect( -16, 16, 32, 16 ), displayText() );
00039         
00040         createProperty( "0-minValue", Variant::Type::Double );
00041         property("0-minValue")->setCaption( i18n("Minimum Value") );
00042         property("0-minValue")->setMinValue(1e-12);
00043         property("0-minValue")->setMaxValue(1e12);
00044         property("0-minValue")->setValue(1e-3);
00045         
00046         createProperty( "1-maxValue", Variant::Type::Double );
00047         property("1-maxValue")->setCaption( i18n("Maximum Value") );
00048         property("1-maxValue")->setMinValue(1e-12);
00049         property("1-maxValue")->setMaxValue(1e12);
00050         property("1-maxValue")->setValue(1e3);
00051 }
00052 
00053 
00054 Meter::~Meter()
00055 {
00056 }
00057 
00058 
00059 void Meter::dataChanged()
00060 {
00061         m_minValue = dataDouble("0-minValue");
00062         m_maxValue = dataDouble("1-maxValue");
00063         setChanged();
00064 }
00065 
00066 void Meter::stepNonLogic()
00067 {
00068         if (b_firstRun)
00069         {
00070                 p_displayText->setText(displayText());
00071                 updateAttachedPositioning();
00072                 setChanged();
00073                 property("0-minValue")->setUnit(m_unit);
00074                 property("1-maxValue")->setUnit(m_unit);
00075                 b_firstRun = false;
00076         }
00077                 
00078         const double v = meterValue();
00079         if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) {
00080                 b_timerStarted = true;
00081         }
00082         
00083         if (b_timerStarted)
00084         {
00085                 m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE;
00086                 m_avgValue += v/LINEAR_UPDATE_RATE;
00087 //              setChanged();
00088                 if ( m_timeSinceUpdate > 0.05 )
00089                 {
00090                         if ( p_displayText->setText(displayText()) );
00091                                 updateAttachedPositioning();
00092                 }
00093         }
00094 }
00095 
00096 void Meter::drawShape( QPainter &p )
00097 {
00098         initPainter(p);
00099         p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() );
00100         p.setPen(QPen(Qt::black,2));
00101         p.setBrush(Qt::black);
00102         
00103         // The proportion between 0.1mV and 10KV, on a logarithmic scale
00104         double prop;
00105         const double abs_value = std::abs(m_old_value);
00106         if ( abs_value <= m_minValue )
00107                 prop = 0.;
00108         else if ( abs_value >= m_maxValue )
00109                 prop = 1.;
00110         else
00111                 prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue );
00112         if ( m_old_value>0 )
00113                 prop *= -1;
00114         double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2
00115         double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2
00116         
00117         int cx = int(x()-16+(width()/2));
00118         int cy = int(y()-16+(height()/2));
00119         p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) );
00120         
00121         QPointArray pa(3);
00122         pa[0] = QPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head
00123         pa[1] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) );
00124         pa[2] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) );
00125         p.drawPolygon(pa);
00126         
00127         deinitPainter(p);
00128 }
00129 
00130 
00131 QString Meter::displayText()
00132 {
00133         double value = m_avgValue/m_timeSinceUpdate;
00134         if ( !std::isfinite(value) ) value = m_old_value;
00135         if ( std::abs((value)) < 1e-9 ) value = 0.;
00136         m_old_value = value;
00137         m_avgValue = 0.;
00138         m_timeSinceUpdate = 0.;
00139         b_timerStarted = false;
00140         return QString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit;
00141 }
00142 //END class Meter
00143 
00144 
00145 //BEGIN class FrequencyMeter
00146 Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
00147 {
00148         return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id );
00149 }
00150 
00151 LibraryItem* FrequencyMeter::libraryItem()
00152 {
00153         return new LibraryItem(
00154                 QString("ec/frequencymeter"),
00155                 i18n("Frequency Meter (TODO)"),
00156                 i18n("Outputs"),
00157                 "frequencymeter.png",
00158                 LibraryItem::lit_component,
00159                 FrequencyMeter::construct );
00160 }
00161 
00162 FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id )
00163         : Meter( icnDocument, newItem, (id) ? id : "frequencymeter" )
00164 {
00165         m_name = i18n("Frequency Meter");
00166         m_desc = i18n("Place this at the point where frequency is to be measured.");
00167         m_unit = "Hz";
00168         
00169         m_probeNode = createPin( 0, -24, 90, "n1" );
00170 }
00171 
00172 FrequencyMeter::~FrequencyMeter()
00173 {
00174 }
00175 
00176 double FrequencyMeter::meterValue()
00177 {
00178         return 0;
00179 }
00180 //END class FrequencyMeter
00181 
00182 
00183 //BEGIN class ECAmmeter
00184 Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
00185 {
00186         return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id );
00187 }
00188 
00189 LibraryItem* ECAmmeter::libraryItem()
00190 {
00191         QStringList ids;
00192         ids << "ec/ammeter" << "ec/ammmeter";
00193         return new LibraryItem(
00194                 ids,
00195                 i18n("Ammeter"),
00196                 i18n("Outputs"),
00197                 "ammeter.png",
00198                 LibraryItem::lit_component,
00199                 ECAmmeter::construct
00200                         );
00201 }
00202 
00203 ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id )
00204         : Meter( icnDocument, newItem, (id) ? id : "ammeter" )
00205 {
00206         m_name = i18n("Ammeter");
00207         m_desc = i18n("Place this in series in the circuit to measure the current flowing.");
00208         setSize( -16, -16, 32, 32 );
00209         m_unit = "A";
00210         
00211         init1PinLeft(0);
00212         init1PinRight(0);
00213         
00214         m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. );
00215 }
00216 
00217 ECAmmeter::~ECAmmeter()
00218 {
00219 }
00220 
00221 double ECAmmeter::meterValue()
00222 {
00223         return -m_voltageSource->cbranchCurrent(0);
00224 }
00225 //END class ECAmmeter
00226 
00227 
00228 //BEGIN class ECVoltmeter
00229 Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
00230 {
00231         return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id );
00232 }
00233 
00234 LibraryItem* ECVoltMeter::libraryItem()
00235 {
00236         return new LibraryItem(
00237                 QString("ec/voltmeter"),
00238                 i18n("Voltmeter"),
00239                 i18n("Outputs"),
00240                 "voltmeter.png",
00241                 LibraryItem::lit_component,
00242                 ECVoltMeter::construct );
00243 }
00244 
00245 ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id )
00246         : Meter( icnDocument, newItem, (id) ? id : "voltmeter" )
00247 {
00248         m_name = i18n("Voltmeter");
00249         m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points.");
00250         m_unit = "V";
00251         
00252         init1PinLeft(0);
00253         init1PinRight(0);
00254 }
00255 
00256 ECVoltMeter::~ECVoltMeter()
00257 {
00258 }
00259 
00260 double ECVoltMeter::meterValue()
00261 {
00262         return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage();
00263 }
00264 //END class ECVoltMeter
00265 

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