00001
00002
00003
00004
00005
00006
00007
00008
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
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
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
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);
00115 double cos_prop = 10*std::cos(prop*1.571);
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) );
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
00143
00144
00145
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
00181
00182
00183
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
00226
00227
00228
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
00265