Min/Max/Delta markers

This commit is contained in:
Jan Käberich 2020-10-20 17:03:49 +02:00
parent b5cd6e0072
commit 49fb02be23
16 changed files with 351 additions and 45 deletions

View file

@ -1,12 +1,22 @@
#include "tracemarker.h"
#include <QPainter>
#include "CustomWidgets/siunitedit.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QDebug>
#include "tracemarkermodel.h"
#include "unit.h"
TraceMarker::TraceMarker(int number)
TraceMarker::TraceMarker(TraceMarkerModel *model, int number)
: editingFrequeny(false),
model(model),
parentTrace(nullptr),
frequency(1000000000),
number(number),
data(0)
data(0),
type(Type::Manual),
delta(nullptr)
{
}
@ -35,6 +45,7 @@ void TraceMarker::assignTrace(Trace *t)
constrainFrequency();
updateSymbol();
parentTrace->addMarker(this);
update();
}
Trace *TraceMarker::trace()
@ -44,9 +55,26 @@ Trace *TraceMarker::trace()
QString TraceMarker::readableData()
{
auto db = 20*log10(abs(data));
auto phase = arg(data);
return QString::number(db, 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4);
switch(type) {
case Type::Manual:
case Type::Maximum:
case Type::Minimum: {
auto db = 20*log10(abs(data));
auto phase = arg(data);
return QString::number(db, 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4);
}
case Type::Delta:
if(!delta) {
return "Invalid delta marker";
} else {
// calculate difference between markers
auto freqDiff = frequency - delta->frequency;
auto valueDiff = data / delta->data;
auto db = 20*log10(abs(valueDiff));
auto phase = arg(valueDiff);
return Unit::ToString(freqDiff, "Hz", " kMG") + " / " + QString::number(db, 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4);
}
}
}
void TraceMarker::setFrequency(double freq)
@ -68,7 +96,8 @@ void TraceMarker::traceDataChanged()
auto tracedata = parentTrace->getData(frequency);
if(tracedata != data) {
data = tracedata;
emit dataChanged(this);
update();
emit rawDataChanged();
}
}
@ -87,6 +116,7 @@ void TraceMarker::updateSymbol()
auto brightness = traceColor.redF() * 0.299 + traceColor.greenF() * 0.587 + traceColor.blueF() * 0.114;
p.setPen((brightness > 0.6) ? Qt::black : Qt::white);
p.drawText(QRectF(0,0,width, height*2.0/3.0), Qt::AlignCenter, QString::number(number));
emit symbolChanged(this);
}
void TraceMarker::constrainFrequency()
@ -101,6 +131,147 @@ void TraceMarker::constrainFrequency()
}
}
void TraceMarker::assignDeltaMarker(TraceMarker *m)
{
if(delta) {
disconnect(delta, &TraceMarker::dataChanged, this, &TraceMarker::update);
}
delta = m;
if(delta && delta != this) {
// this marker has to be updated when the delta marker changes
connect(delta, &TraceMarker::rawDataChanged, this, &TraceMarker::update);
connect(delta, &TraceMarker::deleted, [=](){
delta = nullptr;
update();
});
}
}
void TraceMarker::setNumber(int value)
{
number = value;
updateSymbol();
}
QWidget *TraceMarker::getTypeEditor(QAbstractItemDelegate *delegate)
{
auto c = new QComboBox;
for(auto t : getTypes()) {
c->addItem(typeToString(t));
if(type == t) {
// select this item
c->setCurrentIndex(c->count() - 1);
}
}
if(type == Type::Delta) {
// add additional spinbox to choose corresponding delta marker
auto w = new QWidget;
auto layout = new QHBoxLayout;
layout->addWidget(c);
c->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->setContentsMargins(0,0,0,0);
layout->setMargin(0);
layout->setSpacing(0);
layout->addWidget(new QLabel("to"));
auto spinbox = new QSpinBox;
if(delta) {
spinbox->setValue(delta->number);
}
connect(spinbox, qOverload<int>(&QSpinBox::valueChanged), [=](int newval){
bool found = false;
for(auto m : model->getMarkers()) {
if(m->number == newval) {
assignDeltaMarker(m);
found = true;
break;
}
}
if(!found) {
assignDeltaMarker(nullptr);
}
update();
});
spinbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(spinbox);
w->setLayout(layout);
c->setObjectName("Type");
if(delegate){
connect(c, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) {
emit delegate->commitData(w);
});
}
return w;
} else {
// no delta marker, simply return the combobox
connect(c, qOverload<int>(&QComboBox::currentIndexChanged), [=](int) {
emit delegate->commitData(c);
});
return c;
}
}
void TraceMarker::updateTypeFromEditor(QWidget *w)
{
QComboBox *c;
if(type == Type::Delta) {
c = w->findChild<QComboBox*>("Type");
} else {
c = (QComboBox*) w;
}
for(auto t : getTypes()) {
if(c->currentText() == typeToString(t)) {
if(type != t) {
type = t;
if(type == Type::Delta && !delta) {
// invalid delta marker assigned, attempt to find a matching marker
for(int pass = 0;pass < 3;pass++) {
for(auto m : model->getMarkers()) {
if(pass == 0 && m->parentTrace != parentTrace) {
// ignore markers on different traces in first pass
continue;
}
if(pass <= 1 && m == this) {
// ignore itself on second pass
continue;
}
assignDeltaMarker(m);
break;
}
if(delta) {
break;
}
}
}
emit typeChanged(this);
update();
}
}
}
}
SIUnitEdit *TraceMarker::getSettingsEditor()
{
return new SIUnitEdit("Hz", " kMG");
}
void TraceMarker::update()
{
switch(type) {
case Type::Manual:
// nothing to do
break;
case Type::Maximum:
setFrequency(parentTrace->findExtremumFreq(true));
break;
case Type::Minimum:
setFrequency(parentTrace->findExtremumFreq(false));
break;
}
emit dataChanged(this);
}
Trace *TraceMarker::getTrace() const
{
return parentTrace;