/*************************************************************************** * Copyright (C) 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 "ecnode.h" #include "element.h" #include "libraryitem.h" #include "meter.h" #include "variant.h" #include "voltagesource.h" #include "pin.h" #include "simulator.h" #include #include #include //BEGIN class Meter Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id ) : Component( icnDocument, newItem, id ) { m_bDynamicContent = true; b_timerStarted = false; m_timeSinceUpdate = 0.; m_old_value = 0.; m_avgValue = 0.; b_firstRun = true; setSize( -16, -16, 32, 32 ); p_displayText = addDisplayText( "meter", TQRect( -16, 16, 32, 16 ), displayText() ); createProperty( "0-minValue", Variant::Type::Double ); property("0-minValue")->setCaption( i18n("Minimum Value") ); property("0-minValue")->setMinValue(1e-12); property("0-minValue")->setMaxValue(1e12); property("0-minValue")->setValue(1e-3); createProperty( "1-maxValue", Variant::Type::Double ); property("1-maxValue")->setCaption( i18n("Maximum Value") ); property("1-maxValue")->setMinValue(1e-12); property("1-maxValue")->setMaxValue(1e12); property("1-maxValue")->setValue(1e3); } Meter::~Meter() { } void Meter::dataChanged() { m_minValue = dataDouble("0-minValue"); m_maxValue = dataDouble("1-maxValue"); setChanged(); } void Meter::stepNonLogic() { if (b_firstRun) { p_displayText->setText(displayText()); updateAttachedPositioning(); setChanged(); property("0-minValue")->setUnit(m_unit); property("1-maxValue")->setUnit(m_unit); b_firstRun = false; } const double v = meterValue(); if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) { b_timerStarted = true; } if (b_timerStarted) { m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE; m_avgValue += v/LINEAR_UPDATE_RATE; // setChanged(); if ( m_timeSinceUpdate > 0.05 ) { if ( p_displayText->setText(displayText()) ); updateAttachedPositioning(); } } } void Meter::drawShape( TQPainter &p ) { initPainter(p); p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() ); p.setPen(TQPen(TQt::black,2)); p.setBrush(TQt::black); // The proportion between 0.1mV and 10KV, on a logarithmic scale double prop; const double abs_value = std::abs(m_old_value); if ( abs_value <= m_minValue ) prop = 0.; else if ( abs_value >= m_maxValue ) prop = 1.; else prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue ); if ( m_old_value>0 ) prop *= -1; double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2 double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2 int cx = int(x()-16+(width()/2)); int cy = int(y()-16+(height()/2)); p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) ); TQPointArray pa(3); pa[0] = TQPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head pa[1] = TQPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) ); pa[2] = TQPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) ); p.drawPolygon(pa); deinitPainter(p); } TQString Meter::displayText() { double value = m_avgValue/m_timeSinceUpdate; if ( !std::isfinite(value) ) value = m_old_value; if ( std::abs((value)) < 1e-9 ) value = 0.; m_old_value = value; m_avgValue = 0.; m_timeSinceUpdate = 0.; b_timerStarted = false; return TQString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit; } //END class Meter //BEGIN class FrequencyMeter Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) { return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id ); } LibraryItem* FrequencyMeter::libraryItem() { return new LibraryItem( TQString("ec/frequencymeter"), i18n("Frequency Meter (TODO)"), i18n("Outputs"), "frequencymeter.png", LibraryItem::lit_component, FrequencyMeter::construct ); } FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id ) : Meter( icnDocument, newItem, (id) ? id : "frequencymeter" ) { m_name = i18n("Frequency Meter"); m_desc = i18n("Place this at the point where frequency is to be measured."); m_unit = "Hz"; m_probeNode = createPin( 0, -24, 90, "n1" ); } FrequencyMeter::~FrequencyMeter() { } double FrequencyMeter::meterValue() { return 0; } //END class FrequencyMeter //BEGIN class ECAmmeter Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) { return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id ); } LibraryItem* ECAmmeter::libraryItem() { TQStringList ids; ids << "ec/ammeter" << "ec/ammmeter"; return new LibraryItem( ids, i18n("Ammeter"), i18n("Outputs"), "ammeter.png", LibraryItem::lit_component, ECAmmeter::construct ); } ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id ) : Meter( icnDocument, newItem, (id) ? id : "ammeter" ) { m_name = i18n("Ammeter"); m_desc = i18n("Place this in series in the circuit to measure the current flowing."); setSize( -16, -16, 32, 32 ); m_unit = "A"; init1PinLeft(0); init1PinRight(0); m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. ); } ECAmmeter::~ECAmmeter() { } double ECAmmeter::meterValue() { return -m_voltageSource->cbranchCurrent(0); } //END class ECAmmeter //BEGIN class ECVoltmeter Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id ) { return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id ); } LibraryItem* ECVoltMeter::libraryItem() { return new LibraryItem( TQString("ec/voltmeter"), i18n("Voltmeter"), i18n("Outputs"), "voltmeter.png", LibraryItem::lit_component, ECVoltMeter::construct ); } ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id ) : Meter( icnDocument, newItem, (id) ? id : "voltmeter" ) { m_name = i18n("Voltmeter"); m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points."); m_unit = "V"; init1PinLeft(0); init1PinRight(0); } ECVoltMeter::~ECVoltMeter() { } double ECVoltMeter::meterValue() { return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage(); } //END class ECVoltMeter