#include #include #include #include #include #include #include "displaywidget.h" #include "helpers.h" static const double TimeBaseSteps [] = { 2.0e-6, 5.0e-6, 1.0e-5, 2.0e-5, 5.0e-5, 1.0e-4, 2.0e-4, 5.0e-4, 1.0e-3, 2.0e-3, 5.0e-3, 1.0e-2, 2.0e-2, 5.0e-2, 1.0e-1, 2.0e-1, 5.0e-1, 1.0, }; static const int TimeBaseCounts [] = { 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 2, 1, 1, 1, 1, 1, 1, 1, }; static const double ChannelsSteps [] = { 0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0,20.0,50.0, }; static constexpr double REF_Y = 3.3; // maximum napětí převodníku static constexpr double MAX_Y = double (1 << 12); // 12. bit rozlišení - 4096 steps static constexpr double HALF_Y = 0.5 * MAX_Y; static constexpr double QSCL_Y = 0.5 * HALF_Y; static constexpr double STEP_Y = REF_Y / MAX_Y; // jeden krok ve Voltech static constexpr unsigned T_SIZE = 1u << 10; static constexpr unsigned T_MASK = T_SIZE - 1u; DisplayWidget::DisplayWidget(QWidget * p) : QWidget(p), pcol(), ACopy(), BCopy(), m_forward(), m_inverse(), background(), m_ts(nullptr), ChA (T_SIZE), ChB(T_SIZE), m_items (MOVE_VALUE), m_timeBase(6), m_ChBase(0), m_timeCount(0u) { x_lenght = T_SIZE; m_time.a = 200.0; m_time.b = 300.0; m_volt.a = -1.0 / STEP_Y; m_volt.b = +1.0 / STEP_Y; m_channels.a = ChannelsSteps[3]; m_channels.b = ChannelsSteps[3]; m_offset.a = 0; m_offset.b = 0; marker_type = MARKER_TIME; m_TrgSource = 0; int n = 0; for (QPointF & e : ChA) { const QPointF p (n++, 0); e = p; } n = 0; for (QPointF & e : ChB) { const QPointF p (n++, 0); e = p; } m_continual = false; m_cont_limit = 0; m_cont_pass = 0; } DisplayWidget::~DisplayWidget() { } void DisplayWidget::SendTrigerChan(int n) { m_TrgSource = n; drawBackground(); update(); } void DisplayWidget::MarkerChanged (int n, bool b) { if (!b) return; // qDebug ("Marker : %d -> %s", n, b ? "true" : "false"); // OK switch (n) { case 0: marker_type = MARKER_TIME; break; case 1: marker_type = MARKER_VOLT_A; break; case 2: marker_type = MARKER_VOLT_B; break; default : break; } drawBackground(); update(); } void DisplayWidget::TriggerValues(int n) { m_items = static_cast(n); } static constexpr double FMULT = 1.189207115002721; static constexpr double IMULT = 1.0 / FMULT; void DisplayWidget::wheelEvent(QWheelEvent * event) { if (m_ts == nullptr) return; const QPoint d = event->angleDelta(); const double increment = d.y() > 0 ? +1 : -1; const double zy = -m_inverse.m22(); switch (m_items) { case MOVE_VALUE: { m_ts->value += uint16_t (increment * zy); emit SettingsChanged (m_items); } break; case MOVE_OFSET: { m_ts->offset += increment; emit SettingsChanged (m_items); } break; case MOVE_MARKERA: { if (marker_type == MARKER_TIME) m_time.a += increment; else m_volt.a += increment * zy; } break; case MOVE_MARKERB: { if (marker_type == MARKER_TIME) m_time.b += increment; else m_volt.b += increment * zy; } break; case TIME_ZOOM: { const double mx = FMULT * double (size().width()) / x_lenght; if ((m_forward.m11() > mx) or (increment > 0)) { // limit to window const QMatrix m = increment > 0 ? QMatrix (FMULT,0,0,1,0,0) : QMatrix (IMULT,0,0,1,0,0); m_forward *= m; m_inverse = m_forward.inverted(); } } break; case OFSET_A: { m_offset.a += increment * zy; } break; case OFSET_B: { m_offset.b += increment * zy; } break; default : { qDebug ("wheelEvent : %d", int (m_items)); } break; } drawBackground(); update(); QWidget::wheelEvent(event); } void DisplayWidget::mousePressEvent(QMouseEvent * event) { if (m_ts == nullptr) return; const QPointF dp = m_inverse.map (event->pos ()); const double ofs = m_TrgSource ? m_offset.b : m_offset.a; // qDebug ("dp:[%g, %g] %g", dp.x(), dp.y(), ofs); switch (m_items) { case MOVE_VALUE: { m_ts->value = dp.y() - ofs + HALF_Y; // qDebug("Set Triger : %d", m_ts->value); emit SettingsChanged (m_items); } break; case MOVE_OFSET: { m_ts->offset = dp.x(); emit SettingsChanged (m_items); } break; case MOVE_MARKERA: { if (marker_type == MARKER_TIME) m_time.a = dp.x(); else m_volt.a = dp.y(); } break; case MOVE_MARKERB: { if (marker_type == MARKER_TIME) m_time.b = dp.x(); else m_volt.b = dp.y(); } break; case OFSET_A: { m_offset.a = dp.y(); } break; case OFSET_B: { m_offset.b = dp.y(); } break; case TIME_ZOOM: QWidget::mousePressEvent(event); return; default : { qDebug ("mousePressEvent : %d", int (m_items)); } break; } drawBackground(); update(); QWidget::mousePressEvent(event); } void DisplayWidget::resizeEvent(QResizeEvent * event) { const QSize sz = event->size(); reloadMatrix (sz); QImage tmpi (sz, QImage::Format_ARGB32); background = tmpi; drawBackground(); QWidget::resizeEvent(event); } void DisplayWidget::paintEvent(QPaintEvent * event) { QPainter p (this); p.drawImage(event->rect(), background); drawCurrent(p); QPen pa (pcol.colA, 2); QPen pb (pcol.colB, 2); p.setPen(pb); QMatrix mb (m_forward); mb.translate(0, m_offset.b - HALF_Y); p.drawPolyline (mb.map(ChB)); p.setPen(pa); QMatrix ma (m_forward); ma.translate(0, m_offset.a - HALF_Y); p.drawPolyline (ma.map(ChA)); } void DisplayWidget::drawCurrent(QPainter & p) { if (!m_continual) return; const QPen pen (QColor(192,192,192)); p.setPen (pen); QLineF vl (QPointF(m_timeCount, -QSCL_Y), QPointF(m_timeCount, +QSCL_Y)); p.drawLine (m_forward.map (vl)); // Stávající poloha v kontinuálním módu } void DisplayWidget::setTrigger(TrigerSettings * ts) { m_ts = ts; } void DisplayWidget::DispChannels(QVector cha, QVector chb) { ACopy = cha; BCopy = chb; if (reloadData()) update(); } bool DisplayWidget::reloadData () { const size_t Alen = ACopy.size(); const size_t Blen = BCopy.size(); const size_t Amin = Alen < T_SIZE ? Alen : T_SIZE; const size_t Bmin = Blen < T_SIZE ? Blen : T_SIZE; if ((Alen == 1u) and (Blen == 1u)) { // kontinuální mód m_continual = true; const QPointF pta (m_timeCount, ACopy [0]), ptb (m_timeCount, BCopy [0]); ChA[m_timeCount] = pta; ChB[m_timeCount] = ptb; m_timeCount += 1u; m_timeCount &= T_MASK; m_cont_pass += 1; if (m_cont_pass >= m_cont_limit) { m_cont_pass = 0; return true; } else { return false; } } m_continual = false; for (unsigned n=0u; n Blen ? Alen : Blen; if (l != x_lenght) { x_lenght = l; reloadMatrix (size()); } return true; } void DisplayWidget::reloadMatrix(const QSize & sz) { const double xm = sz.width(); const double ym = sz.height(); const double xz = xm / (x_lenght); // převod zpět ma pixely const double yz = ym / (MAX_Y); const QMatrix tm (xz,0,0,-yz, 0, 0.5 * ym); m_forward = tm; m_inverse = m_forward.inverted(); } void DisplayWidget::TimeBaseRange(int n) { m_timeBase = n; m_cont_limit = TimeBaseCounts [m_timeBase]; //qDebug("count = %d", m_cont_limit); reloadMatrix (size()); drawBackground(); update(); } void DisplayWidget::drawBackground() { QPainter p (&background); QRect r = background.rect(); p.fillRect (r, QBrush(Qt::black, Qt::SolidPattern)); if (!m_ts) return; const double yb = 0.0, ye = HALF_Y; const double xb = 0.0, xe = x_lenght; // rastr QPen pg (QColor(64,64,64), 1); p.setPen(pg); const double dx = 100.0; for (double x=xb; xoffset, m_ts->value + ofs); QPen pc (QColor(0,128,255), 1); p.setPen(pc); const qreal pos = 30.0; const QLineF hline = m_forward.map(QLine(xb, trg.y(), xe, trg.y())); const QLineF vline = m_forward.map(QLine(trg.x(), -ye, trg.x(), ye)); QPointF vb = vline.p1() + QPointF(0,-pos), ve = vline.p2() + QPointF(0,+pos); p.drawLine (hline); p.drawLine (QLineF(vb,ve)); // markers QPen pm (QColor(255,255,0,196), 1); p.setPen(pm); if (marker_type == MARKER_TIME) { const QLineF ma = m_forward.map(QLine (m_time.a, -ye, m_time.a, ye)); const QLineF mb = m_forward.map(QLine (m_time.b, -ye, m_time.b, ye)); vb = ma.p1() + QPointF(0,-pos), ve = ma.p2() + QPointF(0,+pos); p.drawLine (QLineF(vb, ve)); vb = mb.p1() + QPointF(0,-pos), ve = mb.p2() + QPointF(0,+pos); p.drawLine (QLineF(vb, ve)); } else { const QLineF ma (xb, m_volt.a, xe, m_volt.a); const QLineF mb (xb, m_volt.b, xe, m_volt.b); p.drawLine (m_forward.map(ma)); p.drawLine (m_forward.map(mb)); } // offsets QPen ofpen(pcol.colA); QVectordashes; const qreal gap = 10; dashes << gap << gap; ofpen.setDashPattern(dashes); p.setPen (ofpen); const QLineF oa (xb, m_offset.a, xe, m_offset.a); p.drawLine (m_forward.map(oa)); ofpen.setColor(pcol.colB); ofpen.setDashPattern(dashes); ofpen.setDashOffset(gap); p.setPen (ofpen); const QLineF ob (xb, m_offset.b, xe, m_offset.b); p.drawLine (m_forward.map(ob)); // text p.setPen (QPen (pcol.colT)); QFont font = p.font(); font.setPixelSize(16); p.setFont (font); QString desc; const double xz = TimeBaseSteps [m_timeBase]; const int my = r.size().height() - 10; desc.sprintf("T=%ss/d, ChA %gV, ChB %gV", ing_fmt (xz * dx).c_str(), m_channels.a, m_channels.b); p.drawText(10,20, desc); if (marker_type == MARKER_TIME) { const double delta = xz * (m_time.b - m_time.a); const double freq = delta == 0.0 ? 0.0 : 1.0 / delta; desc.sprintf("Marker A: %ss, Marker B: %ss, Δ=%ss, f=%sHz", ing_fmt(xz * m_time.a).c_str(), ing_fmt(xz * m_time.b).c_str(), ing_fmt(delta).c_str(), ing_fmt(freq).c_str()); } else { const double ofs = - (marker_type == MARKER_VOLT_A ? m_offset.a : m_offset.b); double scl = 0.0; if (marker_type == MARKER_VOLT_A) { p.setPen (QPen (pcol.colA)); scl = m_channels.a; } else { p.setPen (QPen (pcol.colB)); scl = m_channels.b; } //qDebug("scl = %g, a=%g, b=%g, oa=%g, ob=%g", scl, m_volt.a, m_volt.b, m_offset.a, m_offset.b); const double yz = STEP_Y * scl; const double delta = yz * (m_volt.b - m_volt.a), va = m_volt.a + ofs, vb = m_volt.b + ofs; desc.sprintf("Marker A: %sV, Marker B: %sV, Δ=%sV", ing_fmt(yz * va).c_str(), ing_fmt(yz * vb).c_str(), ing_fmt(delta).c_str()); } p.drawText(10,my, desc); } void DisplayWidget::SendVoltage(int ch, int n) { switch (ch) { case 0: m_channels.a = ChannelsSteps [n]; break; case 1: m_channels.b = ChannelsSteps [n]; break; default: break; } // qDebug ("Scale: %d => %g,%g", ch, m_channels.a, m_channels.b); drawBackground(); update(); } void DisplayWidget::reloadChRange(int a, int b) { m_channels.a = ChannelsSteps [a]; m_channels.b = ChannelsSteps [b]; drawBackground(); update(); } void DisplayWidget::saveSettings(QSettings & setting) { setting.setValue("TimeA", m_time.a); setting.setValue("TimeB", m_time.b); setting.setValue("VoltA", m_volt.a); setting.setValue("VoltB", m_volt.b); setting.setValue("OfsA" , m_offset.a); setting.setValue("OfsB" , m_offset.b); } void DisplayWidget::restSettings(QSettings & setting) { m_time.a = setting.value("TimeA").toDouble(); m_time.b = setting.value("TimeB").toDouble(); m_volt.a = setting.value("VoltA").toDouble(); m_volt.b = setting.value("VoltB").toDouble(); m_offset.a = setting.value("OfsA").toDouble(); m_offset.b = setting.value("OfsB").toDouble(); drawBackground(); update(); }