Merge branch 'master' into trace_math
This commit is contained in:
commit
692bb85b5d
@ -6,6 +6,7 @@
|
|||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
SIUnitEdit::SIUnitEdit(QString unit, QString prefixes, int precision, QWidget *parent)
|
SIUnitEdit::SIUnitEdit(QString unit, QString prefixes, int precision, QWidget *parent)
|
||||||
: QLineEdit(parent)
|
: QLineEdit(parent)
|
||||||
@ -88,6 +89,30 @@ bool SIUnitEdit::eventFilter(QObject *, QEvent *event)
|
|||||||
// online found clumsy way to select all text when clicked!?!
|
// online found clumsy way to select all text when clicked!?!
|
||||||
// just selectAll() alone does _not_ work!
|
// just selectAll() alone does _not_ work!
|
||||||
QTimer::singleShot(0, this, &SIUnitEdit::continueEditing);
|
QTimer::singleShot(0, this, &SIUnitEdit::continueEditing);
|
||||||
|
} else if(event->type() == QEvent::Wheel) {
|
||||||
|
if(_value == 0.0) {
|
||||||
|
// can't figure out step size with zero value
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto wheel = static_cast<QWheelEvent*>(event);
|
||||||
|
// most mousewheel have 15 degree increments, the reported delta is in 1/8th degree -> 120
|
||||||
|
auto increment = wheel->angleDelta().y() / 120.0;
|
||||||
|
// round toward bigger step in case of special higher resolution mousewheel
|
||||||
|
unsigned int steps = abs(increment > 0 ? ceil(increment) : floor(increment));
|
||||||
|
int sign = increment > 0 ? 1 : -1;
|
||||||
|
// figure out step increment
|
||||||
|
auto newVal = _value;
|
||||||
|
while(steps > 0) {
|
||||||
|
// do update in multiple steps because the step size could change inbetween
|
||||||
|
constexpr int nthDigit = 3;
|
||||||
|
auto step_size = pow(10, floor(log10(abs(newVal))) - nthDigit + 1);
|
||||||
|
newVal += step_size * sign;
|
||||||
|
steps--;
|
||||||
|
}
|
||||||
|
setValue(newVal);
|
||||||
|
continueEditing();
|
||||||
|
setFocus();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -173,6 +173,11 @@ void Trace::removeMarker(TraceMarker *m)
|
|||||||
|
|
||||||
void Trace::updateTimeDomainData()
|
void Trace::updateTimeDomainData()
|
||||||
{
|
{
|
||||||
|
if(_data.size() < 2) {
|
||||||
|
// can't compute anything
|
||||||
|
timeDomain.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// using namespace std::chrono;
|
// using namespace std::chrono;
|
||||||
// auto starttime = duration_cast< milliseconds >(
|
// auto starttime = duration_cast< milliseconds >(
|
||||||
// system_clock::now().time_since_epoch()
|
// system_clock::now().time_since_epoch()
|
||||||
@ -228,7 +233,7 @@ void Trace::updateTimeDomainData()
|
|||||||
t.impedance = numeric_limits<double>::quiet_NaN();
|
t.impedance = numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
last_step += t.impulseResponse;
|
last_step += t.impulseResponse;
|
||||||
timeDomain.push_back(t);
|
timeDomain[i] = t;
|
||||||
}
|
}
|
||||||
// auto duration = duration_cast< milliseconds >(
|
// auto duration = duration_cast< milliseconds >(
|
||||||
// system_clock::now().time_since_epoch()
|
// system_clock::now().time_since_epoch()
|
||||||
|
@ -227,6 +227,7 @@ void TracePlot::dropEvent(QDropEvent *event)
|
|||||||
}
|
}
|
||||||
dropPending = false;
|
dropPending = false;
|
||||||
dropTrace = nullptr;
|
dropTrace = nullptr;
|
||||||
|
replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TracePlot::dragLeaveEvent(QDragLeaveEvent *event)
|
void TracePlot::dragLeaveEvent(QDragLeaveEvent *event)
|
||||||
@ -234,7 +235,7 @@ void TracePlot::dragLeaveEvent(QDragLeaveEvent *event)
|
|||||||
Q_UNUSED(event)
|
Q_UNUSED(event)
|
||||||
dropPending = false;
|
dropPending = false;
|
||||||
dropTrace = nullptr;
|
dropTrace = nullptr;
|
||||||
triggerReplot();
|
replot();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<TracePlot *> TracePlot::getPlots()
|
std::set<TracePlot *> TracePlot::getPlots()
|
||||||
|
@ -355,8 +355,8 @@ void TraceXYPlot::draw(QPainter &p)
|
|||||||
p.setPen(pen);
|
p.setPen(pen);
|
||||||
auto nPoints = numTraceSamples(t);
|
auto nPoints = numTraceSamples(t);
|
||||||
for(unsigned int j=1;j<nPoints;j++) {
|
for(unsigned int j=1;j<nPoints;j++) {
|
||||||
auto last = transformY(t, j-1, YAxis[i].type);
|
auto last = traceToCoordinate(t, j-1, YAxis[i].type);
|
||||||
auto now = transformY(t, j, YAxis[i].type);
|
auto now = traceToCoordinate(t, j, YAxis[i].type);
|
||||||
|
|
||||||
if(isnan(last.y()) || isnan(now.y()) || isinf(last.y()) || isinf(now.y())) {
|
if(isnan(last.y()) || isnan(now.y()) || isinf(last.y()) || isinf(now.y())) {
|
||||||
continue;
|
continue;
|
||||||
@ -393,7 +393,7 @@ void TraceXYPlot::draw(QPainter &p)
|
|||||||
if (xPosition < XAxis.rangeMin || xPosition > XAxis.rangeMax) {
|
if (xPosition < XAxis.rangeMin || xPosition > XAxis.rangeMax) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QPointF markerPoint = QPointF(xPosition, transformY(m->getData(), YAxis[i].type));
|
QPointF markerPoint = QPointF(xPosition, traceToCoordinate(m->getData(), YAxis[i].type));
|
||||||
auto point = plotValueToPixel(markerPoint, i);
|
auto point = plotValueToPixel(markerPoint, i);
|
||||||
if(!plotRect.contains(point)) {
|
if(!plotRect.contains(point)) {
|
||||||
// out of screen
|
// out of screen
|
||||||
@ -451,7 +451,12 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
{
|
{
|
||||||
auto createEvenlySpacedTicks = [](vector<double>& ticks, double start, double stop, double step) {
|
auto createEvenlySpacedTicks = [](vector<double>& ticks, double start, double stop, double step) {
|
||||||
ticks.clear();
|
ticks.clear();
|
||||||
for(double tick = start; tick - stop < numeric_limits<double>::epsilon() ;tick+= step) {
|
if(start > stop) {
|
||||||
|
swap(start, stop);
|
||||||
|
}
|
||||||
|
step = abs(step);
|
||||||
|
constexpr unsigned int maxTicks = 100;
|
||||||
|
for(double tick = start; tick - stop < numeric_limits<double>::epsilon() && ticks.size() <= maxTicks;tick+= step) {
|
||||||
ticks.push_back(tick);
|
ticks.push_back(tick);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -494,6 +499,10 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
|| tracesAxis[1].find(t.first) != tracesAxis[1].end());
|
|| tracesAxis[1].find(t.first) != tracesAxis[1].end());
|
||||||
auto trace = t.first;
|
auto trace = t.first;
|
||||||
if(enabled && trace->isVisible()) {
|
if(enabled && trace->isVisible()) {
|
||||||
|
if(!numTraceSamples(trace)) {
|
||||||
|
// empty trace, do not use for automatic axis calculation
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// this trace is currently displayed
|
// this trace is currently displayed
|
||||||
double trace_min = std::numeric_limits<double>::max();
|
double trace_min = std::numeric_limits<double>::max();
|
||||||
double trace_max = std::numeric_limits<double>::lowest();
|
double trace_max = std::numeric_limits<double>::lowest();
|
||||||
@ -520,14 +529,13 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(min >= max) {
|
if(min < max) {
|
||||||
// still at initial values, no traces are active, leave axis unchanged
|
// found min/max values
|
||||||
return;
|
|
||||||
}
|
|
||||||
XAxis.rangeMin = min;
|
XAxis.rangeMin = min;
|
||||||
XAxis.rangeMax = max;
|
XAxis.rangeMax = max;
|
||||||
XAxis.rangeDiv = createAutomaticTicks(XAxis.ticks, min, max, 8);
|
XAxis.rangeDiv = createAutomaticTicks(XAxis.ticks, min, max, 8);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0;i<2;i++) {
|
for(int i=0;i<2;i++) {
|
||||||
if(!YAxis[i].autorange) {
|
if(!YAxis[i].autorange) {
|
||||||
@ -539,7 +547,12 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
for(auto t : tracesAxis[i]) {
|
for(auto t : tracesAxis[i]) {
|
||||||
unsigned int samples = numTraceSamples(t);
|
unsigned int samples = numTraceSamples(t);
|
||||||
for(unsigned int j=0;j<samples;j++) {
|
for(unsigned int j=0;j<samples;j++) {
|
||||||
auto point = transformY(t, j, YAxis[i].type);
|
auto point = traceToCoordinate(t, j, YAxis[i].type);
|
||||||
|
|
||||||
|
if(point.x() < XAxis.rangeMin || point.x() > XAxis.rangeMax) {
|
||||||
|
// this point is not in the displayed X range, skip for auto Y range calculation
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(point.y() > max) {
|
if(point.y() > max) {
|
||||||
max = point.y();
|
max = point.y();
|
||||||
@ -557,7 +570,6 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
YAxis[i].rangeDiv = createAutomaticTicks(YAxis[i].ticks, min, max, 8);
|
YAxis[i].rangeDiv = createAutomaticTicks(YAxis[i].ticks, min, max, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
triggerReplot();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type)
|
QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type)
|
||||||
@ -620,7 +632,7 @@ bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double TraceXYPlot::transformY(std::complex<double> data, TraceXYPlot::YAxisType type)
|
double TraceXYPlot::traceToCoordinate(std::complex<double> data, TraceXYPlot::YAxisType type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case YAxisType::Magnitude:
|
case YAxisType::Magnitude:
|
||||||
@ -646,7 +658,7 @@ double TraceXYPlot::transformY(std::complex<double> data, TraceXYPlot::YAxisType
|
|||||||
return numeric_limits<double>::quiet_NaN();
|
return numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointF TraceXYPlot::transformY(Trace *t, unsigned int sample, TraceXYPlot::YAxisType type)
|
QPointF TraceXYPlot::traceToCoordinate(Trace *t, unsigned int sample, TraceXYPlot::YAxisType type)
|
||||||
{
|
{
|
||||||
QPointF ret = QPointF(numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN());
|
QPointF ret = QPointF(numeric_limits<double>::quiet_NaN(), numeric_limits<double>::quiet_NaN());
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -654,8 +666,8 @@ QPointF TraceXYPlot::transformY(Trace *t, unsigned int sample, TraceXYPlot::YAxi
|
|||||||
case YAxisType::Phase:
|
case YAxisType::Phase:
|
||||||
case YAxisType::VSWR: {
|
case YAxisType::VSWR: {
|
||||||
auto d = t->sample(sample);
|
auto d = t->sample(sample);
|
||||||
ret.setY(transformY(d.y, type));
|
ret.setY(traceToCoordinate(d.S, type));
|
||||||
ret.setX(d.x);
|
ret.setX(d.frequency);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case YAxisType::Impulse:
|
case YAxisType::Impulse:
|
||||||
@ -702,12 +714,12 @@ unsigned int TraceXYPlot::numTraceSamples(Trace *t)
|
|||||||
|
|
||||||
QPoint TraceXYPlot::dataToPixel(Trace::Data d)
|
QPoint TraceXYPlot::dataToPixel(Trace::Data d)
|
||||||
{
|
{
|
||||||
if(d.x < XAxis.rangeMin || d.x > XAxis.rangeMax) {
|
if(d.frequency < XAxis.rangeMin || d.frequency > XAxis.rangeMax) {
|
||||||
return QPoint();
|
return QPoint();
|
||||||
}
|
}
|
||||||
auto y = transformY(d.y, YAxis[0].type);
|
auto y = traceToCoordinate(d.S, YAxis[0].type);
|
||||||
QPoint p;
|
QPoint p;
|
||||||
p.setX(Util::Scale<double>(d.x, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
p.setX(Util::Scale<double>(d.frequency, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
||||||
p.setY(Util::Scale<double>(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0));
|
p.setY(Util::Scale<double>(y, YAxis[0].rangeMin, YAxis[0].rangeMax, plotAreaBottom, 0));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -736,7 +748,7 @@ QPoint TraceXYPlot::markerToPixel(TraceMarker *m)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
QPointF plotPoint;
|
QPointF plotPoint;
|
||||||
plotPoint.setY(transformY(m->getData(), YAxis[0].type));
|
plotPoint.setY(traceToCoordinate(m->getData(), YAxis[0].type));
|
||||||
if(m->isTimeDomain()) {
|
if(m->isTimeDomain()) {
|
||||||
auto timedata = m->getTimeData();
|
auto timedata = m->getTimeData();
|
||||||
if(XAxis.type == XAxisType::Distance) {
|
if(XAxis.type == XAxisType::Distance) {
|
||||||
@ -760,13 +772,13 @@ double TraceXYPlot::nearestTracePoint(Trace *t, QPoint pixel)
|
|||||||
double closestXpos = 0;
|
double closestXpos = 0;
|
||||||
auto samples = numTraceSamples(t);
|
auto samples = numTraceSamples(t);
|
||||||
for(unsigned int i=0;i<samples;i++) {
|
for(unsigned int i=0;i<samples;i++) {
|
||||||
auto point = transformY(t, i, YAxis[0].type);
|
auto point = traceToCoordinate(t, i, YAxis[0].type);
|
||||||
if(isnan(point.x()) || isnan(point.y())) {
|
if(isnan(point.x()) || isnan(point.y())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto plotPoint = plotValueToPixel(point, 0);
|
auto plotPoint = plotValueToPixel(point, 0);
|
||||||
auto diff = plotPoint - pixel;
|
QPointF diff = plotPoint - pixel;
|
||||||
unsigned int distance = diff.x() * diff.x() + diff.y() * diff.y();
|
auto distance = diff.x() * diff.x() + diff.y() * diff.y();
|
||||||
if(distance < closestDistance) {
|
if(distance < closestDistance) {
|
||||||
closestDistance = distance;
|
closestDistance = distance;
|
||||||
closestXpos = point.x();
|
closestXpos = point.x();
|
||||||
|
@ -58,8 +58,8 @@ private:
|
|||||||
QString AxisTypeToName(YAxisType type);
|
QString AxisTypeToName(YAxisType type);
|
||||||
void enableTraceAxis(Trace *t, int axis, bool enabled);
|
void enableTraceAxis(Trace *t, int axis, bool enabled);
|
||||||
bool supported(Trace *t, YAxisType type);
|
bool supported(Trace *t, YAxisType type);
|
||||||
double transformY(std::complex<double> data, YAxisType type);
|
double traceToCoordinate(std::complex<double> data, YAxisType type);
|
||||||
QPointF transformY(Trace *t, unsigned int sample, YAxisType type);
|
QPointF traceToCoordinate(Trace *t, unsigned int sample, YAxisType type);
|
||||||
unsigned int numTraceSamples(Trace *t);
|
unsigned int numTraceSamples(Trace *t);
|
||||||
QPoint dataToPixel(Trace::Data d);
|
QPoint dataToPixel(Trace::Data d);
|
||||||
QPoint plotValueToPixel(QPointF plotValue, int Yaxis);
|
QPoint plotValueToPixel(QPointF plotValue, int Yaxis);
|
||||||
|
Loading…
Reference in New Issue
Block a user