278 lines
8.8 KiB
C++
278 lines
8.8 KiB
C++
|
#include <QPainter>
|
||
|
#include <QResizeEvent>
|
||
|
#include <QPaintEvent>
|
||
|
#include <QWheelEvent>
|
||
|
#include <QSettings>
|
||
|
#include <math.h>
|
||
|
#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 double ChannelsSteps [] = {
|
||
|
1.0, 2.0, 5.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 STEP_Y = REF_Y / MAX_Y; // jeden krok ve Voltech
|
||
|
|
||
|
DisplayWidget::DisplayWidget(QWidget * p) : QWidget(p), ACopy(), BCopy(), m_forward(), m_inverse(), background(), m_ts(nullptr),
|
||
|
ChA (1024), ChB(1024), m_items (MOVE_VALUE), m_timeBase(6), m_ChBase(0), m_timeCount(0u) {
|
||
|
x_lenght = 1024;
|
||
|
m_time.a = 200.0;
|
||
|
m_time.b = 300.0;
|
||
|
m_volt.a = 1.0 / STEP_Y;
|
||
|
m_volt.b = 2.0 / STEP_Y;
|
||
|
marker_type = MARKER_TIME;
|
||
|
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; }
|
||
|
}
|
||
|
DisplayWidget::~DisplayWidget() {
|
||
|
}
|
||
|
void DisplayWidget::MarkerChanged (bool b) {
|
||
|
// qDebug ("Marker : %s", b ? "Time" : "Volt"); // OK
|
||
|
if (b) marker_type = MARKER_TIME;
|
||
|
else marker_type = MARKER_VOLT;
|
||
|
drawBackground();
|
||
|
update();
|
||
|
}
|
||
|
|
||
|
void DisplayWidget::TriggerValues(int n) {
|
||
|
m_items = static_cast<MOVE_ITEMS>(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 int increment = d.y() > 0 ? +1 : -1;
|
||
|
switch (m_items) {
|
||
|
case MOVE_VALUE: {
|
||
|
m_ts->value += increment * 4;
|
||
|
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;
|
||
|
} break;
|
||
|
case MOVE_MARKERB: {
|
||
|
if (marker_type == MARKER_TIME) m_time.b += increment;
|
||
|
else m_volt.b += increment;
|
||
|
} 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;
|
||
|
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 ());
|
||
|
// qDebug ("dp:[%g, %g]", dp.x(), dp.y());
|
||
|
switch (m_items) {
|
||
|
case MOVE_VALUE: {
|
||
|
m_ts->value = dp.y();
|
||
|
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 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);
|
||
|
QPen pa (QColor(0,255, 0,255), 2);
|
||
|
QPen pb (QColor(255,64,0,255), 2);
|
||
|
p.setPen(pb);
|
||
|
p.drawPolyline (m_forward.map(ChB));
|
||
|
p.setPen(pa);
|
||
|
p.drawPolyline (m_forward.map(ChA));
|
||
|
}
|
||
|
void DisplayWidget::setTrigger(TrigerSettings * ts) {
|
||
|
m_ts = ts;
|
||
|
}
|
||
|
void DisplayWidget::DispChannels(QVector<int> cha, QVector<int> chb) {
|
||
|
ACopy = cha;
|
||
|
BCopy = chb;
|
||
|
reloadData();
|
||
|
update();
|
||
|
}
|
||
|
static constexpr unsigned T_SIZE = 1u << 10;
|
||
|
static constexpr unsigned T_MASK = T_SIZE - 1u;
|
||
|
void DisplayWidget::reloadData () {
|
||
|
const int Alen = ACopy.size();
|
||
|
const int Blen = BCopy.size();
|
||
|
QVector<QPointF> va (Alen), vb (Blen);
|
||
|
if (Alen == 1 and Blen == 1) { // kontinuální mód
|
||
|
if (ChA.size() != T_SIZE) { ChA = QPolygonF (T_SIZE); }
|
||
|
if (ChB.size() != T_SIZE) { ChB = QPolygonF (T_SIZE); }
|
||
|
const QPointF pta (m_timeCount, ACopy [0]), ptb (m_timeCount, BCopy [0]);
|
||
|
ChA[m_timeCount] = pta;
|
||
|
ChB[m_timeCount] = ptb;
|
||
|
// printf("mode continuum\n");
|
||
|
m_timeCount += 1u;
|
||
|
m_timeCount &= T_MASK;
|
||
|
return;
|
||
|
}
|
||
|
for (int n=0u; n<Alen; n++) {
|
||
|
const double x = (double (n));
|
||
|
const double y = ( ACopy [n]);
|
||
|
va [n] = QPointF (x,y);
|
||
|
}
|
||
|
ChA = QPolygonF (va);
|
||
|
for (int n=0u; n<Blen; n++) {
|
||
|
const double x = (double (n));
|
||
|
const double y = ( BCopy [n]);
|
||
|
vb [n] = QPointF (x,y);
|
||
|
}
|
||
|
ChB = QPolygonF (vb);
|
||
|
const int l = Alen > Blen ? Alen : Blen;
|
||
|
if (l != x_lenght) {
|
||
|
x_lenght = l;
|
||
|
reloadMatrix (size());
|
||
|
}
|
||
|
}
|
||
|
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, ym);
|
||
|
m_forward = tm;
|
||
|
m_inverse = m_forward.inverted();
|
||
|
}
|
||
|
|
||
|
void DisplayWidget::TimeBaseRange(int n) {
|
||
|
m_timeBase = n;
|
||
|
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 = MAX_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; x<xe; x+=dx) {
|
||
|
const QLineF yline (x, yb, x, ye);
|
||
|
p.drawLine (m_forward.map(yline));
|
||
|
}
|
||
|
const double dv = 0.5;
|
||
|
const double dy = dv / STEP_Y;
|
||
|
for (double y=yb; y<ye; y+=dy) {
|
||
|
const QLineF xline (xb, y, xe, y);
|
||
|
p.drawLine (m_forward.map(xline));
|
||
|
}
|
||
|
// triger
|
||
|
QPointF trg (m_ts->offset, m_ts->value);
|
||
|
QPen pc (QColor(0,0,255), 1);
|
||
|
p.setPen(pc);
|
||
|
const QLineF hline (xb, trg.y(), xe, trg.y());
|
||
|
const QLineF vline (trg.x(), yb, trg.x(), ye);
|
||
|
p.drawLine (m_forward.map(hline));
|
||
|
p.drawLine (m_forward.map(vline));
|
||
|
// markers
|
||
|
QPen pm (QColor(255,255,0,196), 2);
|
||
|
p.setPen(pm);
|
||
|
if (marker_type == MARKER_TIME) {
|
||
|
const QLineF ma (m_time.a, yb, m_time.a, ye);
|
||
|
const QLineF mb (m_time.b, yb, m_time.b, ye);
|
||
|
p.drawLine (m_forward.map(ma));
|
||
|
p.drawLine (m_forward.map(mb));
|
||
|
} 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));
|
||
|
}
|
||
|
// text
|
||
|
p.setPen (QPen (QColor(255,255,0)));
|
||
|
QFont font = p.font();
|
||
|
font.setPixelSize(16);
|
||
|
p.setFont (font);
|
||
|
QString desc;
|
||
|
const double xz = TimeBaseSteps [m_timeBase];
|
||
|
const double yz = STEP_Y;
|
||
|
const int my = r.size().height() - 10;
|
||
|
desc.sprintf("T=%ss/d; A,B=%gV/d", ing_fmt (xz * dx).c_str() , dv);
|
||
|
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 delta = yz * (m_volt.b - m_volt.a);
|
||
|
desc.sprintf("Marker A: %sV, Marker B: %sV, Δ=%sV", ing_fmt(yz * m_volt.a).c_str(), ing_fmt(yz * m_volt.b).c_str(),
|
||
|
ing_fmt(delta).c_str());
|
||
|
}
|
||
|
p.drawText(10,my, desc);
|
||
|
}
|
||
|
void DisplayWidget::saveSettings(QSettings & setting) {
|
||
|
setting.setValue("TimeBaseIndex", m_timeBase);
|
||
|
setting.setValue("TimeA", m_time.a);
|
||
|
setting.setValue("TimeB", m_time.b);
|
||
|
setting.setValue("VoltA", m_volt.a);
|
||
|
setting.setValue("VoltB", m_volt.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();
|
||
|
}
|