partial reconstruction from qwt to manual plotting
This commit is contained in:
parent
ef97d54913
commit
25196fbc30
@ -39,6 +39,7 @@ HEADERS += \
|
||||
Traces/tracexyplot.h \
|
||||
Traces/xyplotaxisdialog.h \
|
||||
Util/qpointervariant.h \
|
||||
Util/util.h \
|
||||
VNA/portextension.h \
|
||||
VNA/vna.h \
|
||||
appwindow.h \
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <QApplication>
|
||||
#include <QActionGroup>
|
||||
#include "CustomWidgets/informationbox.h"
|
||||
#include <QDebug>
|
||||
|
||||
SpectrumAnalyzer::SpectrumAnalyzer(AppWindow *window)
|
||||
: Mode(window, "Spectrum Analyzer"),
|
||||
|
@ -6,13 +6,16 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>224</width>
|
||||
<height>69</height>
|
||||
<width>302</width>
|
||||
<height>76</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Smithchart Setup</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
|
@ -1,5 +1,9 @@
|
||||
#include "traceplot.h"
|
||||
#include "tracemarker.h"
|
||||
#include "preferences.h"
|
||||
#include <QPainter>
|
||||
#include <QMimeData>
|
||||
#include <QDebug>
|
||||
|
||||
std::set<TracePlot*> TracePlot::plots;
|
||||
|
||||
@ -16,6 +20,8 @@ TracePlot::TracePlot(TraceModel &model, QWidget *parent)
|
||||
// get notified when the span changes
|
||||
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TracePlot::updateSpan));
|
||||
plots.insert(this);
|
||||
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
||||
TracePlot::~TracePlot()
|
||||
@ -42,7 +48,7 @@ void TracePlot::enableTrace(Trace *t, bool enabled)
|
||||
disconnect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved);
|
||||
}
|
||||
updateContextMenu();
|
||||
triggerReplot();
|
||||
replot();
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,6 +84,71 @@ void TracePlot::contextMenuEvent(QContextMenuEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void TracePlot::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
auto pref = Preferences::getInstance();
|
||||
QPainter p(this);
|
||||
// p.setRenderHint(QPainter::Antialiasing);
|
||||
// fill background
|
||||
p.setBackground(QBrush(pref.General.graphColors.background));
|
||||
p.fillRect(0, 0, width(), height(), QBrush(pref.General.graphColors.background));
|
||||
|
||||
// show names of active traces
|
||||
QFont font = p.font();
|
||||
font.setPixelSize(12);
|
||||
p.setFont(font);
|
||||
int x = 1;
|
||||
for(auto t : traces) {
|
||||
if(!t.second || !t.first->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
auto textArea = QRect(x, 0, width() - x, marginTop);
|
||||
QRect usedArea;
|
||||
p.setPen(t.first->color());
|
||||
p.drawText(textArea, 0, t.first->name() + " ", &usedArea);
|
||||
x += usedArea.width();
|
||||
if(x >= width()) {
|
||||
// used up all available space
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p.setViewport(marginLeft, marginTop, width() - marginLeft - marginRight, height() - marginTop - marginBottom);
|
||||
p.setWindow(0, 0, width() - marginLeft - marginRight, height() - marginTop - marginBottom);
|
||||
|
||||
draw(p);
|
||||
}
|
||||
|
||||
void TracePlot::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat("trace/pointer")) {
|
||||
auto data = event->mimeData()->data("trace/pointer");
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
quintptr dropPtr;
|
||||
stream >> dropPtr;
|
||||
auto trace = (Trace*) dropPtr;
|
||||
if(supported(trace)) {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TracePlot::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat("trace/pointer")) {
|
||||
auto data = event->mimeData()->data("trace/pointer");
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
quintptr dropPtr;
|
||||
stream >> dropPtr;
|
||||
auto trace = (Trace*) dropPtr;
|
||||
qDebug() << "Dropped" << trace << ", encoded as" << stream;
|
||||
|
||||
if(supported(trace)) {
|
||||
enableTrace(trace, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::set<TracePlot *> TracePlot::getPlots()
|
||||
{
|
||||
return plots;
|
||||
|
@ -29,16 +29,21 @@ protected:
|
||||
// need to be called in derived class constructor
|
||||
void initializeTraceInfo();
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
virtual void updateContextMenu(){};
|
||||
virtual bool supported(Trace *t) = 0;
|
||||
virtual void replot(){};
|
||||
virtual void replot(){update();};
|
||||
virtual void draw(QPainter& p) = 0;
|
||||
std::map<Trace*, bool> traces;
|
||||
QMenu *contextmenu;
|
||||
QTime lastUpdate;
|
||||
bool markedForDeletion;
|
||||
|
||||
static std::set<TracePlot*> plots;
|
||||
|
||||
// handle trace drops
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
protected slots:
|
||||
void newTraceAvailable(Trace *t);
|
||||
void traceDeleted(Trace *t);
|
||||
@ -46,6 +51,10 @@ protected slots:
|
||||
virtual void markerAdded(TraceMarker *m);
|
||||
virtual void markerRemoved(TraceMarker *m);
|
||||
protected:
|
||||
static constexpr unsigned int marginTop = 20;
|
||||
static constexpr unsigned int marginBottom = 0;
|
||||
static constexpr unsigned int marginLeft = 0;
|
||||
static constexpr unsigned int marginRight = 0;
|
||||
double sweep_fmin, sweep_fmax;
|
||||
TraceModel &model;
|
||||
|
||||
|
@ -40,15 +40,13 @@ void TraceSmithChart::axisSetupDialog()
|
||||
|
||||
QPoint TraceSmithChart::plotToPixel(std::complex<double> S)
|
||||
{
|
||||
QPoint ret;
|
||||
ret.setX(S.real() * plotToPixelXScale + plotToPixelXOffset);
|
||||
ret.setY(S.imag() * plotToPixelYScale + plotToPixelYOffset);
|
||||
return ret;
|
||||
return transform.map(QPoint(S.real() * smithCoordMax, -S.imag() * smithCoordMax));
|
||||
}
|
||||
|
||||
std::complex<double> TraceSmithChart::pixelToPlot(const QPoint &pos)
|
||||
{
|
||||
return complex<double>((pos.x() - plotToPixelXOffset) / plotToPixelXScale, (pos.y() - plotToPixelYOffset) / plotToPixelYScale);
|
||||
QPointF inv = transform.inverted().map(pos);
|
||||
return complex<double>(inv.x()/smithCoordMax, -inv.y()/smithCoordMax);
|
||||
}
|
||||
|
||||
void TraceSmithChart::mousePressEvent(QMouseEvent *event)
|
||||
@ -111,43 +109,45 @@ void TraceSmithChart::mouseMoveEvent(QMouseEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceSmithChart::draw(QPainter * painter, double width_factor) {
|
||||
painter->setPen(QPen(1.0 * width_factor));
|
||||
painter->setBrush(palette().windowText());
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
// // Display parameter name
|
||||
// QFont font = painter->font();
|
||||
// font.setPixelSize(48);
|
||||
// font.setBold(true);
|
||||
// painter->setFont(font);
|
||||
// painter->drawText(-512, -512, title);
|
||||
|
||||
void TraceSmithChart::draw(QPainter &p) {
|
||||
p.setBrush(palette().windowText());
|
||||
auto pref = Preferences::getInstance();
|
||||
|
||||
// translate coordinate system so that the smith chart sits in the origin has a size of 1
|
||||
auto w = p.window();
|
||||
p.translate(w.width()/2, w.height()/2);
|
||||
auto scale = qMin(w.height(), w.width()) / (2.0 * smithCoordMax);
|
||||
p.scale(scale, scale);
|
||||
|
||||
transform = p.transform();
|
||||
|
||||
// Outer circle
|
||||
painter->setPen(QPen(pref.General.graphColors.axis, 1.5 * width_factor));
|
||||
auto pen = QPen(pref.General.graphColors.axis);
|
||||
pen.setCosmetic(true);
|
||||
p.setPen(pen);
|
||||
QRectF rectangle(-smithCoordMax, -smithCoordMax, 2*smithCoordMax, 2*smithCoordMax);
|
||||
painter->drawArc(rectangle, 0, 5760);
|
||||
p.drawArc(rectangle, 0, 5760);
|
||||
|
||||
constexpr int Circles = 6;
|
||||
painter->setPen(QPen(pref.General.graphColors.divisions, 0.5 * width_factor, Qt::DashLine));
|
||||
pen = QPen(pref.General.graphColors.divisions, 0.5, Qt::DashLine);
|
||||
pen.setCosmetic(true);
|
||||
p.setPen(pen);
|
||||
for(int i=1;i<Circles;i++) {
|
||||
rectangle.adjust(2*smithCoordMax/Circles, smithCoordMax/Circles, 0, -smithCoordMax/Circles);
|
||||
painter->drawArc(rectangle, 0, 5760);
|
||||
rectangle.adjust(2.0*smithCoordMax/Circles, smithCoordMax/Circles, 0, -smithCoordMax/Circles);
|
||||
p.drawArc(rectangle, 0, 5760);
|
||||
}
|
||||
|
||||
painter->drawLine(-smithCoordMax, 0, smithCoordMax, 0);
|
||||
p.drawLine(-smithCoordMax, 0, smithCoordMax, 0);
|
||||
constexpr std::array<double, 5> impedanceLines = {10, 25, 50, 100, 250};
|
||||
for(auto z : impedanceLines) {
|
||||
z /= ReferenceImpedance;
|
||||
auto radius = smithCoordMax * 1.0/z;
|
||||
auto radius = smithCoordMax/z;
|
||||
double span = M_PI - 2 * atan(radius/smithCoordMax);
|
||||
span *= 5760 / (2 * M_PI);
|
||||
QRectF rectangle(smithCoordMax - radius, -2*radius, 2 * radius, 2 * radius);
|
||||
painter->drawArc(rectangle, 4320 - span, span);
|
||||
QRectF rectangle(smithCoordMax - radius, -2 * radius, 2 * radius, 2 * radius);
|
||||
p.drawArc(rectangle, 4320 - span, span);
|
||||
rectangle = QRectF(smithCoordMax - radius, 0, 2 * radius, 2 * radius);
|
||||
painter->drawArc(rectangle, 1440, span);
|
||||
p.drawArc(rectangle, 1440, span);
|
||||
}
|
||||
|
||||
for(auto t : traces) {
|
||||
@ -160,7 +160,9 @@ void TraceSmithChart::draw(QPainter * painter, double width_factor) {
|
||||
// trace marked invisible
|
||||
continue;
|
||||
}
|
||||
painter->setPen(QPen(trace->color(), 1.5 * width_factor));
|
||||
pen = QPen(trace->color(), 1.5);
|
||||
pen.setCosmetic(true);
|
||||
p.setPen(pen);
|
||||
int nPoints = trace->size();
|
||||
for(int i=1;i<nPoints;i++) {
|
||||
auto last = trace->sample(i-1);
|
||||
@ -175,7 +177,7 @@ void TraceSmithChart::draw(QPainter * painter, double width_factor) {
|
||||
last.S *= smithCoordMax;
|
||||
now.S *= smithCoordMax;
|
||||
// draw line
|
||||
painter->drawLine(std::real(last.S), -std::imag(last.S), std::real(now.S), -std::imag(now.S));
|
||||
p.drawLine(std::real(last.S), -std::imag(last.S), std::real(now.S), -std::imag(now.S));
|
||||
}
|
||||
if(trace->size() > 0) {
|
||||
// only draw markers if the trace has at least one point
|
||||
@ -187,38 +189,33 @@ void TraceSmithChart::draw(QPainter * painter, double width_factor) {
|
||||
auto coords = m->getData();
|
||||
coords *= smithCoordMax;
|
||||
auto symbol = m->getSymbol();
|
||||
symbol = symbol.scaled(symbol.width()*width_factor, symbol.height()*width_factor);
|
||||
painter->drawPixmap(coords.real() - symbol.width()/2, -coords.imag() - symbol.height(), symbol);
|
||||
symbol = symbol.scaled(symbol.width()/scale, symbol.height()/scale);
|
||||
p.drawPixmap(coords.real() - symbol.width()/2, -coords.imag() - symbol.height(), symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TraceSmithChart::replot()
|
||||
{
|
||||
update();
|
||||
}
|
||||
//void TraceSmithChart::paintEvent(QPaintEvent * /* the event */)
|
||||
//{
|
||||
// auto pref = Preferences::getInstance();
|
||||
// QPainter painter(this);
|
||||
// painter.setRenderHint(QPainter::Antialiasing);
|
||||
// painter.setBackground(QBrush(pref.General.graphColors.background));
|
||||
// painter.fillRect(0, 0, width(), height(), QBrush(pref.General.graphColors.background));
|
||||
|
||||
void TraceSmithChart::paintEvent(QPaintEvent * /* the event */)
|
||||
{
|
||||
auto pref = Preferences::getInstance();
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBackground(QBrush(pref.General.graphColors.background));
|
||||
painter.fillRect(0, 0, width(), height(), QBrush(pref.General.graphColors.background));
|
||||
// double side = qMin(width(), height()) * screenUsage;
|
||||
|
||||
double side = qMin(width(), height()) * screenUsage;
|
||||
// //painter.setViewport((width()-side)/2, (height()-side)/2, side, side);
|
||||
// //painter.setWindow(-smithCoordMax, -smithCoordMax, 2*smithCoordMax, 2*smithCoordMax);
|
||||
|
||||
painter.setViewport((width()-side)/2, (height()-side)/2, side, side);
|
||||
painter.setWindow(-smithCoordMax, -smithCoordMax, 2*smithCoordMax, 2*smithCoordMax);
|
||||
// plotToPixelXOffset = width()/2;
|
||||
// plotToPixelYOffset = height()/2;
|
||||
// plotToPixelXScale = side/2;
|
||||
// plotToPixelYScale = -side/2;
|
||||
|
||||
plotToPixelXOffset = width()/2;
|
||||
plotToPixelYOffset = height()/2;
|
||||
plotToPixelXScale = side/2;
|
||||
plotToPixelYScale = -side/2;
|
||||
|
||||
draw(&painter, 2*smithCoordMax/side);
|
||||
}
|
||||
// draw(painter, 2*smithCoordMax/side);
|
||||
//}
|
||||
|
||||
void TraceSmithChart::updateContextMenu()
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "traceplot.h"
|
||||
#include <QPen>
|
||||
#include <QPainterPath>
|
||||
#include <QTransform>
|
||||
|
||||
class TraceSmithChart : public TracePlot
|
||||
{
|
||||
@ -15,18 +16,17 @@ public slots:
|
||||
protected:
|
||||
static constexpr double ReferenceImpedance = 50.0;
|
||||
static constexpr double screenUsage = 0.9;
|
||||
static constexpr int smithCoordMax = 4096;
|
||||
static constexpr double smithCoordMax = 4096;
|
||||
|
||||
QPoint plotToPixel(std::complex<double> S);
|
||||
std::complex<double> pixelToPlot(const QPoint &pos);
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
//void paintEvent(QPaintEvent *event) override;
|
||||
virtual void updateContextMenu() override;
|
||||
bool supported(Trace *t) override;
|
||||
void draw(QPainter * painter, double width_factor);
|
||||
void replot() override;
|
||||
virtual void draw(QPainter& painter) override;
|
||||
QPen textPen;
|
||||
QPen chartLinesPen;
|
||||
QPen thinPen;
|
||||
@ -39,8 +39,7 @@ protected:
|
||||
/// Path for the thick arcs
|
||||
QPainterPath thickArcsPath;
|
||||
|
||||
double plotToPixelXOffset, plotToPixelXScale;
|
||||
double plotToPixelYOffset, plotToPixelYScale;
|
||||
QTransform transform;
|
||||
TraceMarker *selectedMarker;
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,9 @@
|
||||
#include "traceimportdialog.h"
|
||||
#include "traceexportdialog.h"
|
||||
#include <QFileDialog>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
#include <QDebug>
|
||||
|
||||
TraceWidget::TraceWidget(TraceModel &model, QWidget *parent, bool SA) :
|
||||
QWidget(parent),
|
||||
@ -16,6 +19,7 @@ TraceWidget::TraceWidget(TraceModel &model, QWidget *parent, bool SA) :
|
||||
ui->setupUi(this);
|
||||
ui->view->setModel(&model);
|
||||
ui->view->setAutoScroll(false);
|
||||
ui->view->viewport()->installEventFilter(this);
|
||||
installEventFilter(this);
|
||||
createCount = 0;
|
||||
}
|
||||
@ -54,6 +58,44 @@ bool TraceWidget::eventFilter(QObject *, QEvent *event)
|
||||
model.removeTrace(ui->view->currentIndex().row());
|
||||
return true;
|
||||
}
|
||||
} else if(event->type() == QEvent::MouseButtonPress) {
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
auto index = ui->view->indexAt(mouseEvent->pos());
|
||||
if(index.isValid()) {
|
||||
dragStartPosition = mouseEvent->pos();
|
||||
dragTrace = model.trace(index.row());
|
||||
} else {
|
||||
dragTrace = nullptr;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if(event->type() == QEvent::MouseMove) {
|
||||
auto mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
if (!(mouseEvent->buttons() & Qt::LeftButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!dragTrace) {
|
||||
return false;
|
||||
}
|
||||
if ((mouseEvent->pos() - dragStartPosition).manhattanLength()
|
||||
< QApplication::startDragDistance()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
|
||||
QByteArray encodedPointer;
|
||||
QDataStream stream(&encodedPointer, QIODevice::WriteOnly);
|
||||
stream << quintptr(dragTrace);
|
||||
qDebug() << "Dragging" << dragTrace << ", encoded as" << stream;
|
||||
|
||||
mimeData->setData("trace/pointer", encodedPointer);
|
||||
drag->setMimeData(mimeData);
|
||||
|
||||
drag->exec(Qt::CopyAction);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -22,17 +22,15 @@ public slots:
|
||||
private slots:
|
||||
void on_remove_clicked();
|
||||
void on_edit_clicked();
|
||||
|
||||
void on_view_doubleClicked(const QModelIndex &index);
|
||||
|
||||
void on_view_clicked(const QModelIndex &index);
|
||||
|
||||
void on_bImport_clicked();
|
||||
|
||||
void on_bExport_clicked();
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
QPoint dragStartPosition;
|
||||
Trace *dragTrace;
|
||||
Ui::TraceWidget *ui;
|
||||
TraceModel &model;
|
||||
int createCount;
|
||||
|
@ -46,6 +46,15 @@
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragOnly</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
|
@ -1,22 +1,25 @@
|
||||
#include "tracexyplot.h"
|
||||
#include <QGridLayout>
|
||||
#include "qwtplotpiecewisecurve.h"
|
||||
#include "qwt_series_data.h"
|
||||
//#include "qwtplotpiecewisecurve.h"
|
||||
//#include "qwt_series_data.h"
|
||||
#include "trace.h"
|
||||
#include <cmath>
|
||||
#include <QFrame>
|
||||
#include <qwt_plot_canvas.h>
|
||||
#include <qwt_scale_div.h>
|
||||
#include <qwt_plot_layout.h>
|
||||
//#include <qwt_plot_canvas.h>
|
||||
//#include <qwt_scale_div.h>
|
||||
//#include <qwt_plot_layout.h>
|
||||
#include "tracemarker.h"
|
||||
#include <qwt_symbol.h>
|
||||
#include <qwt_picker_machine.h>
|
||||
//#include <qwt_symbol.h>
|
||||
//#include <qwt_picker_machine.h>
|
||||
#include "xyplotaxisdialog.h"
|
||||
#include <preferences.h>
|
||||
#include <QPainter>
|
||||
#include "Util/util.h"
|
||||
#include "unit.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
set<TraceXYPlot*> TraceXYPlot::allPlots;
|
||||
//set<TraceXYPlot*> TraceXYPlot::allPlots;
|
||||
|
||||
const set<TraceXYPlot::YAxisType> TraceXYPlot::YAxisTypes = {TraceXYPlot::YAxisType::Disabled,
|
||||
TraceXYPlot::YAxisType::Magnitude,
|
||||
@ -54,65 +57,65 @@ static double TimeAxisTransformation(TraceXYPlot::YAxisType type, Trace *t, int
|
||||
return numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
class QwtTraceSeries : public QwtSeriesData<QPointF> {
|
||||
public:
|
||||
QwtTraceSeries(Trace &t, TraceXYPlot::YAxisType Ytype, const TraceXYPlot *plot)
|
||||
: QwtSeriesData<QPointF>(),
|
||||
Ytype(Ytype),
|
||||
plot(plot),
|
||||
t(t){}
|
||||
size_t size() const override {
|
||||
switch(Ytype) {
|
||||
case TraceXYPlot::YAxisType::Magnitude:
|
||||
case TraceXYPlot::YAxisType::Phase:
|
||||
case TraceXYPlot::YAxisType::VSWR:
|
||||
return t.size();
|
||||
case TraceXYPlot::YAxisType::Impulse:
|
||||
case TraceXYPlot::YAxisType::Step:
|
||||
case TraceXYPlot::YAxisType::Impedance:
|
||||
return t.getTDR().size();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
QPointF sample(size_t i) const override {
|
||||
switch(Ytype) {
|
||||
case TraceXYPlot::YAxisType::Magnitude:
|
||||
case TraceXYPlot::YAxisType::Phase:
|
||||
case TraceXYPlot::YAxisType::VSWR: {
|
||||
Trace::Data d = t.sample(i);
|
||||
QPointF p;
|
||||
p.setX(d.frequency);
|
||||
p.setY(FrequencyAxisTransformation(Ytype, d.S));
|
||||
return p;
|
||||
}
|
||||
case TraceXYPlot::YAxisType::Impulse:
|
||||
case TraceXYPlot::YAxisType::Step:
|
||||
case TraceXYPlot::YAxisType::Impedance: {
|
||||
auto sample = t.getTDR()[i];
|
||||
QPointF p;
|
||||
if(plot->XAxis.type == TraceXYPlot::XAxisType::Time) {
|
||||
p.setX(sample.time);
|
||||
} else {
|
||||
p.setX(sample.distance);
|
||||
}
|
||||
p.setY(TimeAxisTransformation(Ytype, &t, i));
|
||||
return p;
|
||||
}
|
||||
default:
|
||||
return QPointF();
|
||||
}
|
||||
//class QwtTraceSeries : public QwtSeriesData<QPointF> {
|
||||
//public:
|
||||
// QwtTraceSeries(Trace &t, TraceXYPlot::YAxisType Ytype, const TraceXYPlot *plot)
|
||||
// : QwtSeriesData<QPointF>(),
|
||||
// Ytype(Ytype),
|
||||
// plot(plot),
|
||||
// t(t){}
|
||||
// size_t size() const override {
|
||||
// switch(Ytype) {
|
||||
// case TraceXYPlot::YAxisType::Magnitude:
|
||||
// case TraceXYPlot::YAxisType::Phase:
|
||||
// case TraceXYPlot::YAxisType::VSWR:
|
||||
// return t.size();
|
||||
// case TraceXYPlot::YAxisType::Impulse:
|
||||
// case TraceXYPlot::YAxisType::Step:
|
||||
// case TraceXYPlot::YAxisType::Impedance:
|
||||
// return t.getTDR().size();
|
||||
// default:
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
// QPointF sample(size_t i) const override {
|
||||
// switch(Ytype) {
|
||||
// case TraceXYPlot::YAxisType::Magnitude:
|
||||
// case TraceXYPlot::YAxisType::Phase:
|
||||
// case TraceXYPlot::YAxisType::VSWR: {
|
||||
// Trace::Data d = t.sample(i);
|
||||
// QPointF p;
|
||||
// p.setX(d.frequency);
|
||||
// p.setY(FrequencyAxisTransformation(Ytype, d.S));
|
||||
// return p;
|
||||
// }
|
||||
// case TraceXYPlot::YAxisType::Impulse:
|
||||
// case TraceXYPlot::YAxisType::Step:
|
||||
// case TraceXYPlot::YAxisType::Impedance: {
|
||||
// auto sample = t.getTDR()[i];
|
||||
// QPointF p;
|
||||
// if(plot->XAxis.type == TraceXYPlot::XAxisType::Time) {
|
||||
// p.setX(sample.time);
|
||||
// } else {
|
||||
// p.setX(sample.distance);
|
||||
// }
|
||||
// p.setY(TimeAxisTransformation(Ytype, &t, i));
|
||||
// return p;
|
||||
// }
|
||||
// default:
|
||||
// return QPointF();
|
||||
// }
|
||||
|
||||
}
|
||||
QRectF boundingRect() const override {
|
||||
return qwtBoundingRect(*this);
|
||||
}
|
||||
// }
|
||||
// QRectF boundingRect() const override {
|
||||
// return qwtBoundingRect(*this);
|
||||
// }
|
||||
|
||||
private:
|
||||
TraceXYPlot::YAxisType Ytype;
|
||||
const TraceXYPlot *plot;
|
||||
Trace &t;
|
||||
};
|
||||
//private:
|
||||
// TraceXYPlot::YAxisType Ytype;
|
||||
// const TraceXYPlot *plot;
|
||||
// Trace &t;
|
||||
//};
|
||||
|
||||
TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
||||
: TracePlot(model, parent),
|
||||
@ -137,35 +140,37 @@ TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
||||
XAxis.rangeMin = 0;
|
||||
XAxis.mode = XAxisMode::UseSpan;
|
||||
|
||||
plot = new QwtPlot(this);
|
||||
|
||||
auto canvas = new QwtPlotCanvas(plot);
|
||||
canvas->setFrameStyle(QFrame::Plain);
|
||||
plot->setCanvas(canvas);
|
||||
plot->setAutoFillBackground(true);
|
||||
grid = new QwtPlotGrid();
|
||||
grid->attach(plot);
|
||||
setColorFromPreferences();
|
||||
|
||||
auto selectPicker = new XYplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
selectPicker->setStateMachine(new QwtPickerClickPointMachine);
|
||||
// plot = new QwtPlot(this);
|
||||
|
||||
drawPicker = new XYplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
drawPicker->setStateMachine(new QwtPickerDragPointMachine);
|
||||
drawPicker->setTrackerPen(QPen(Qt::white));
|
||||
// auto canvas = new QwtPlotCanvas(plot);
|
||||
// canvas->setFrameStyle(QFrame::Plain);
|
||||
// plot->setCanvas(canvas);
|
||||
// plot->setAutoFillBackground(true);
|
||||
// grid = new QwtPlotGrid();
|
||||
// grid->attach(plot);
|
||||
// setColorFromPreferences();
|
||||
|
||||
// Marker selection
|
||||
connect(selectPicker, SIGNAL(selected(QPointF)), this, SLOT(clicked(QPointF)));;
|
||||
// Marker movement
|
||||
connect(drawPicker, SIGNAL(moved(QPointF)), this, SLOT(moved(QPointF)));
|
||||
// auto selectPicker = new XYplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
// selectPicker->setStateMachine(new QwtPickerClickPointMachine);
|
||||
|
||||
auto layout = new QGridLayout;
|
||||
layout->addWidget(plot);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(layout);
|
||||
plot->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
// drawPicker = new XYplotPicker(plot->xBottom, plot->yLeft, QwtPicker::NoRubberBand, QwtPicker::ActiveOnly, plot->canvas());
|
||||
// drawPicker->setStateMachine(new QwtPickerDragPointMachine);
|
||||
// drawPicker->setTrackerPen(QPen(Qt::white));
|
||||
|
||||
// // Marker selection
|
||||
// connect(selectPicker, SIGNAL(selected(QPointF)), this, SLOT(clicked(QPointF)));;
|
||||
// // Marker movement
|
||||
// connect(drawPicker, SIGNAL(moved(QPointF)), this, SLOT(moved(QPointF)));
|
||||
|
||||
// auto layout = new QGridLayout;
|
||||
// layout->addWidget(plot);
|
||||
// layout->setContentsMargins(0, 0, 0, 0);
|
||||
// setLayout(layout);
|
||||
// plot->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
initializeTraceInfo();
|
||||
setAutoFillBackground(true);
|
||||
// setAutoFillBackground(true);
|
||||
|
||||
// Setup default axis
|
||||
setYAxis(0, YAxisType::Magnitude, false, false, -120, 20, 10);
|
||||
@ -174,18 +179,18 @@ TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
||||
updateSpan(0, 6000000000);
|
||||
setXAxis(XAxisType::Frequency, XAxisMode::UseSpan, 0, 6000000000, 600000000);
|
||||
|
||||
allPlots.insert(this);
|
||||
// allPlots.insert(this);
|
||||
}
|
||||
|
||||
TraceXYPlot::~TraceXYPlot()
|
||||
{
|
||||
for(int axis = 0;axis < 2;axis++) {
|
||||
for(auto pd : curves[axis]) {
|
||||
delete pd.second.curve;
|
||||
}
|
||||
}
|
||||
delete drawPicker;
|
||||
allPlots.erase(this);
|
||||
// for(int axis = 0;axis < 2;axis++) {
|
||||
// for(auto pd : curves[axis]) {
|
||||
// delete pd.second.curve;
|
||||
// }
|
||||
// }
|
||||
// delete drawPicker;
|
||||
// allPlots.erase(this);
|
||||
}
|
||||
|
||||
void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool autorange, double min, double max, double div)
|
||||
@ -213,16 +218,16 @@ void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool
|
||||
|
||||
for(auto t : tracesAxis[axis]) {
|
||||
// supported but needs an adjusted QwtSeriesData
|
||||
auto td = curves[axis][t];
|
||||
td.data = createQwtSeriesData(*t, axis);
|
||||
// auto td = curves[axis][t];
|
||||
// td.data = createQwtSeriesData(*t, axis);
|
||||
// call to setSamples deletes old QwtSeriesData
|
||||
td.curve->setSamples(td.data);
|
||||
// td.curve->setSamples(td.data);
|
||||
if(axis == 0) {
|
||||
// update marker data
|
||||
auto marker = t->getMarkers();
|
||||
for(auto m : marker) {
|
||||
markerDataChanged(m);
|
||||
}
|
||||
// auto marker = t->getMarkers();
|
||||
// for(auto m : marker) {
|
||||
// markerDataChanged(m);
|
||||
// }
|
||||
}
|
||||
if(isTDRtype(type)) {
|
||||
t->addTDRinterest();
|
||||
@ -234,14 +239,15 @@ void TraceXYPlot::setYAxis(int axis, TraceXYPlot::YAxisType type, bool log, bool
|
||||
YAxis[axis].rangeMin = min;
|
||||
YAxis[axis].rangeMax = max;
|
||||
YAxis[axis].rangeDiv = div;
|
||||
updateAxisTicks();
|
||||
// enable/disable y axis
|
||||
auto qwtaxis = axis == 0 ? QwtPlot::yLeft : QwtPlot::yRight;
|
||||
plot->enableAxis(qwtaxis, type != YAxisType::Disabled);
|
||||
if(autorange) {
|
||||
plot->setAxisAutoScale(qwtaxis, true);
|
||||
} else {
|
||||
plot->setAxisScale(qwtaxis, min, max, div);
|
||||
}
|
||||
// auto qwtaxis = axis == 0 ? QwtPlot::yLeft : QwtPlot::yRight;
|
||||
// plot->enableAxis(qwtaxis, type != YAxisType::Disabled);
|
||||
// if(autorange) {
|
||||
// plot->setAxisAutoScale(qwtaxis, true);
|
||||
// } else {
|
||||
// plot->setAxisScale(qwtaxis, min, max, div);
|
||||
// }
|
||||
updateContextMenu();
|
||||
replot();
|
||||
}
|
||||
@ -253,6 +259,7 @@ void TraceXYPlot::setXAxis(XAxisType type, XAxisMode mode, double min, double ma
|
||||
XAxis.rangeMin = min;
|
||||
XAxis.rangeMax = max;
|
||||
XAxis.rangeDiv = div;
|
||||
updateAxisTicks();
|
||||
}
|
||||
|
||||
void TraceXYPlot::enableTrace(Trace *t, bool enabled)
|
||||
@ -264,13 +271,19 @@ void TraceXYPlot::enableTrace(Trace *t, bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceXYPlot::updateGraphColors()
|
||||
void TraceXYPlot::updateSpan(double min, double max)
|
||||
{
|
||||
for(auto p : allPlots) {
|
||||
p->setColorFromPreferences();
|
||||
}
|
||||
TracePlot::updateSpan(min, max);
|
||||
updateAxisTicks();
|
||||
}
|
||||
|
||||
//void TraceXYPlot::updateGraphColors()
|
||||
//{
|
||||
// for(auto p : allPlots) {
|
||||
// p->setColorFromPreferences();
|
||||
// }
|
||||
//}
|
||||
|
||||
bool TraceXYPlot::isTDRtype(TraceXYPlot::YAxisType type)
|
||||
{
|
||||
switch(type) {
|
||||
@ -335,10 +348,276 @@ bool TraceXYPlot::supported(Trace *)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TraceXYPlot::replot()
|
||||
void TraceXYPlot::draw(QPainter &p)
|
||||
{
|
||||
updateXAxis();
|
||||
plot->replot();
|
||||
p.setBrush(palette().windowText());
|
||||
auto pref = Preferences::getInstance();
|
||||
|
||||
constexpr int yAxisSpace = 50;
|
||||
constexpr int yAxisDisabledSpace = 10;
|
||||
constexpr int xAxisSpace = 30;
|
||||
auto w = p.window();
|
||||
auto pen = QPen(pref.General.graphColors.axis, 0);
|
||||
pen.setCosmetic(true);
|
||||
p.setPen(pen);
|
||||
int plotAreaLeft = YAxis[0].type == YAxisType::Disabled ? yAxisDisabledSpace : yAxisSpace;
|
||||
int plotAreaWidth = w.width();
|
||||
int plotAreaBottom = w.height() - xAxisSpace;
|
||||
if(YAxis[0].type != YAxisType::Disabled) {
|
||||
plotAreaWidth -= yAxisSpace;
|
||||
} else {
|
||||
plotAreaWidth -= yAxisDisabledSpace;
|
||||
}
|
||||
if(YAxis[1].type != YAxisType::Disabled) {
|
||||
plotAreaWidth -= yAxisSpace;
|
||||
} else {
|
||||
plotAreaWidth -= yAxisDisabledSpace;
|
||||
}
|
||||
p.drawRect(plotAreaLeft, 0, plotAreaWidth, w.height()-xAxisSpace);
|
||||
|
||||
// draw axis types
|
||||
QString labelX;
|
||||
switch(XAxis.type) {
|
||||
case XAxisType::Frequency: labelX = "Frequency"; break;
|
||||
case XAxisType::Time: labelX = "Time"; break;
|
||||
case XAxisType::Distance: labelX = "Distance"; break;
|
||||
}
|
||||
auto font = p.font();
|
||||
font.setPixelSize(AxisLabelSize);
|
||||
p.setFont(font);
|
||||
p.drawText(QRect(0, w.height()-AxisLabelSize*1.5, w.width(), AxisLabelSize*1.5), Qt::AlignHCenter, labelX);
|
||||
// draw X ticks
|
||||
// this only works for evenly distributed ticks:
|
||||
auto max = qMax(abs(XAxis.ticks.front()), abs(XAxis.ticks.back()));
|
||||
auto step = abs(XAxis.ticks[0] - XAxis.ticks[1]);
|
||||
int significantDigits = floor(log10(max)) - floor(log10(step)) + 1;
|
||||
bool displayFullFreq = significantDigits <= 5;
|
||||
constexpr int displayLastDigits = 4;
|
||||
if(!displayFullFreq) {
|
||||
auto fullFreq = Unit::ToString(XAxis.ticks.front(), "", " kMG", significantDigits);
|
||||
|
||||
auto front = fullFreq;
|
||||
front.truncate(fullFreq.size() - displayLastDigits);
|
||||
auto back = fullFreq;
|
||||
back.remove(0, front.size());
|
||||
back.append("..");
|
||||
p.setPen(QPen(QColor("orange")));
|
||||
QRect bounding;
|
||||
p.drawText(QRect(2, plotAreaBottom + AxisLabelSize + 5, w.width(), AxisLabelSize), 0, front, &bounding);
|
||||
p.setPen(pref.General.graphColors.axis);
|
||||
p.drawText(QRect(bounding.x() + bounding.width(), plotAreaBottom + AxisLabelSize + 5, w.width(), AxisLabelSize), 0, back);
|
||||
}
|
||||
|
||||
for(auto t : XAxis.ticks) {
|
||||
auto xCoord = Util::Scale<double>(t, XAxis.ticks.front(), XAxis.ticks.back(), plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||
auto tickValue = Unit::ToString(t, "", "fpnum kMG", significantDigits);
|
||||
p.setPen(QPen(pref.General.graphColors.axis, 1));
|
||||
if(displayFullFreq) {
|
||||
p.drawText(QRect(xCoord - 40, plotAreaBottom + 5, 80, AxisLabelSize), Qt::AlignHCenter, tickValue);
|
||||
} else {
|
||||
tickValue.remove(0, tickValue.size() - displayLastDigits);
|
||||
QRect bounding;
|
||||
p.drawText(QRect(xCoord - 40, plotAreaBottom + 5, 80, AxisLabelSize), Qt::AlignHCenter, tickValue, &bounding);
|
||||
p.setPen(QPen(QColor("orange")));
|
||||
p.drawText(QRect(0, plotAreaBottom + 5, bounding.x() - 1, AxisLabelSize), Qt::AlignRight, "..");
|
||||
p.setPen(QPen(pref.General.graphColors.axis, 1));
|
||||
}
|
||||
p.drawLine(xCoord, plotAreaBottom, xCoord, plotAreaBottom + 2);
|
||||
if(xCoord != plotAreaLeft && xCoord != plotAreaLeft + plotAreaWidth) {
|
||||
p.setPen(QPen(pref.General.graphColors.divisions, 0.5, Qt::DashLine));
|
||||
p.drawLine(xCoord, 0, xCoord, plotAreaBottom);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
if(YAxis[i].type == YAxisType::Disabled) {
|
||||
continue;
|
||||
}
|
||||
QString labelY;
|
||||
p.setPen(QPen(pref.General.graphColors.axis, 1));
|
||||
switch(YAxis[i].type) {
|
||||
case YAxisType::Magnitude: labelY = "Magnitude"; break;
|
||||
case YAxisType::Phase: labelY = "Phase"; break;
|
||||
case YAxisType::VSWR: labelY = "VSWR"; break;
|
||||
case YAxisType::Impulse: labelY = "Impulse Response"; break;
|
||||
case YAxisType::Step: labelY = "Step Response"; break;
|
||||
case YAxisType::Impedance: labelY = "Impedance"; break;
|
||||
}
|
||||
auto xStart = i == 0 ? 0 : w.width() - AxisLabelSize * 1.5;
|
||||
p.save();
|
||||
p.translate(xStart, w.height()-xAxisSpace);
|
||||
p.rotate(-90);
|
||||
p.drawText(QRect(0, 0, w.height()-xAxisSpace, AxisLabelSize*1.5), Qt::AlignHCenter, labelY);
|
||||
p.restore();
|
||||
// draw ticks
|
||||
if(YAxis[0].type != YAxisType::Disabled) {
|
||||
// this only works for evenly distributed ticks:
|
||||
auto max = qMax(abs(YAxis[i].ticks.front()), abs(YAxis[i].ticks.back()));
|
||||
auto step = abs(YAxis[i].ticks[0] - YAxis[i].ticks[1]);
|
||||
int significantDigits = floor(log10(max)) - floor(log10(step)) + 1;
|
||||
for(auto t : YAxis[i].ticks) {
|
||||
auto yCoord = Util::Scale<double>(t, YAxis[i].rangeMax, YAxis[i].rangeMin, 0, w.height() - xAxisSpace);
|
||||
p.setPen(QPen(pref.General.graphColors.axis, 1));
|
||||
// draw tickmark on axis
|
||||
auto tickStart = i == 0 ? plotAreaLeft : plotAreaLeft + plotAreaWidth;
|
||||
auto tickLen = i == 0 ? -2 : 2;
|
||||
p.drawLine(tickStart, yCoord, tickStart + tickLen, yCoord);
|
||||
auto tickValue = Unit::ToString(t, "", "fpnum kMG", significantDigits);
|
||||
if(i == 0) {
|
||||
p.drawText(QRectF(0, yCoord - AxisLabelSize/2 - 2, tickStart + 2 * tickLen, AxisLabelSize), Qt::AlignRight, tickValue);
|
||||
} else {
|
||||
p.drawText(QRectF(tickStart + 2 * tickLen + 2, yCoord - AxisLabelSize/2 - 2, yAxisSpace, AxisLabelSize), Qt::AlignLeft, tickValue);
|
||||
}
|
||||
|
||||
// tick lines
|
||||
if(yCoord == 0 || yCoord == w.height() - xAxisSpace) {
|
||||
// skip tick lines right on the plot borders
|
||||
continue;
|
||||
}
|
||||
if(i == 0) {
|
||||
// only draw tick lines for primary axis
|
||||
p.setPen(QPen(pref.General.graphColors.divisions, 0.5, Qt::DashLine));
|
||||
p.drawLine(plotAreaLeft, yCoord, plotAreaLeft + plotAreaWidth, yCoord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto toPlotCoordinates = [=](double x, double y, const class YAxis& ax) -> QPointF {
|
||||
QPointF p;
|
||||
p.setX(Util::Scale<double>(x, XAxis.rangeMin, XAxis.rangeMax, plotAreaLeft, plotAreaLeft + plotAreaWidth));
|
||||
p.setY(Util::Scale<double>(y, ax.rangeMin, ax.rangeMax, plotAreaBottom, 0));
|
||||
return p;
|
||||
};
|
||||
|
||||
// plot traces
|
||||
p.setClipRect(QRect(plotAreaLeft + 1, 1, plotAreaWidth - 2, plotAreaBottom - 1));
|
||||
switch(XAxis.type) {
|
||||
case XAxisType::Frequency:
|
||||
for(auto t : tracesAxis[i]) {
|
||||
if(!t->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
pen = QPen(t->color(), 1.5);
|
||||
pen.setCosmetic(true);
|
||||
if(i == 1) {
|
||||
pen.setStyle(Qt::DotLine);
|
||||
} else {
|
||||
pen.setStyle(Qt::SolidLine);
|
||||
}
|
||||
p.setPen(pen);
|
||||
int nPoints = t->size();
|
||||
for(int j=1;j<nPoints;j++) {
|
||||
auto last = t->sample(j-1);
|
||||
auto now = t->sample(j);
|
||||
|
||||
auto yLast = transformFrequencyY(last.S, YAxis[i].type);
|
||||
auto yNow = transformFrequencyY(now.S, YAxis[i].type);
|
||||
|
||||
if(isnan(yLast) || isnan(yNow) || isinf(yLast) || isinf(yNow)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// scale to plot coordinates
|
||||
auto p1 = toPlotCoordinates(last.frequency, yLast, YAxis[i]);
|
||||
auto p2 = toPlotCoordinates(now.frequency, yNow, YAxis[i]);
|
||||
// draw line
|
||||
p.drawLine(p1, p2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XAxisType::Time:
|
||||
case XAxisType::Distance:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
p.setClipping(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TraceXYPlot::updateAxisTicks()
|
||||
{
|
||||
auto createEvenlySpacedTicks = [](vector<double>& ticks, double start, double stop, double step) {
|
||||
ticks.clear();
|
||||
for(double tick = start;tick <= stop;tick+= step) {
|
||||
ticks.push_back(tick);
|
||||
}
|
||||
};
|
||||
|
||||
if(XAxis.mode == XAxisMode::Manual) {
|
||||
createEvenlySpacedTicks(XAxis.ticks, XAxis.rangeMin, XAxis.rangeMax, XAxis.rangeDiv);
|
||||
} else {
|
||||
XAxis.ticks.clear();
|
||||
// automatic mode, figure out limits
|
||||
double max = std::numeric_limits<double>::lowest();
|
||||
double min = std::numeric_limits<double>::max();
|
||||
if(XAxis.mode == XAxisMode::UseSpan) {
|
||||
min = sweep_fmin;
|
||||
max = sweep_fmax;
|
||||
} else if(XAxis.mode == XAxisMode::FitTraces) {
|
||||
for(auto t : traces) {
|
||||
bool enabled = (tracesAxis[0].find(t.first) != tracesAxis[0].end()
|
||||
|| tracesAxis[1].find(t.first) != tracesAxis[1].end());
|
||||
auto trace = t.first;
|
||||
if(enabled && trace->isVisible()) {
|
||||
// this trace is currently displayed
|
||||
double trace_min = std::numeric_limits<double>::max();
|
||||
double trace_max = std::numeric_limits<double>::lowest();
|
||||
switch(XAxis.type) {
|
||||
case XAxisType::Frequency:
|
||||
trace_min = trace->minFreq();
|
||||
trace_max = trace->maxFreq();
|
||||
break;
|
||||
case XAxisType::Time:
|
||||
trace_min = trace->getTDR().front().time;
|
||||
trace_max = trace->getTDR().back().time;
|
||||
break;
|
||||
case XAxisType::Distance:
|
||||
trace_min = trace->getTDR().front().distance;
|
||||
trace_max = trace->getTDR().back().distance;
|
||||
break;
|
||||
}
|
||||
if(trace_min < min) {
|
||||
min = trace_min;
|
||||
}
|
||||
if(trace_max > max) {
|
||||
max = trace_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(min >= max) {
|
||||
// still at initial values, no traces are active, leave axis unchanged
|
||||
return;
|
||||
}
|
||||
XAxis.rangeMin = min;
|
||||
XAxis.rangeMax = max;
|
||||
constexpr int minDivisions = 8;
|
||||
double max_div_step = (max - min) / minDivisions;
|
||||
int zeros = floor(log10(max_div_step));
|
||||
double decimals_shift = pow(10, zeros);
|
||||
max_div_step /= decimals_shift;
|
||||
if(max_div_step >= 5) {
|
||||
max_div_step = 5;
|
||||
} else if(max_div_step >= 2) {
|
||||
max_div_step = 2;
|
||||
} else {
|
||||
max_div_step = 1;
|
||||
}
|
||||
auto div_step = max_div_step * decimals_shift;
|
||||
XAxis.rangeDiv = div_step;
|
||||
// round min up to next multiple of div_step
|
||||
auto start_div = ceil(min / div_step) * div_step;
|
||||
for(double tick = start_div;tick <= max;tick += div_step) {
|
||||
XAxis.ticks.push_back(tick);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
if(!YAxis[i].autorange) {
|
||||
createEvenlySpacedTicks(YAxis[i].ticks, YAxis[i].rangeMin, YAxis[i].rangeMax, YAxis[i].rangeDiv);
|
||||
}
|
||||
}
|
||||
triggerReplot();
|
||||
}
|
||||
|
||||
QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type)
|
||||
@ -354,21 +633,24 @@ QString TraceXYPlot::AxisTypeToName(TraceXYPlot::YAxisType type)
|
||||
|
||||
void TraceXYPlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
{
|
||||
if(axis == 0) {
|
||||
traces[t] = enabled;
|
||||
}
|
||||
bool alreadyEnabled = tracesAxis[axis].find(t) != tracesAxis[axis].end();
|
||||
if(alreadyEnabled != enabled) {
|
||||
if(enabled) {
|
||||
tracesAxis[axis].insert(t);
|
||||
CurveData cd;
|
||||
cd.data = createQwtSeriesData(*t, axis);
|
||||
cd.curve = new QwtPlotPiecewiseCurve();
|
||||
cd.curve->attach(plot);
|
||||
cd.curve->setYAxis(axis == 0 ? QwtPlot::yLeft : QwtPlot::yRight);
|
||||
cd.curve->setSamples(cd.data);
|
||||
curves[axis][t] = cd;
|
||||
// CurveData cd;
|
||||
// cd.data = createQwtSeriesData(*t, axis);
|
||||
// cd.curve = new QwtPlotPiecewiseCurve();
|
||||
// cd.curve->attach(plot);
|
||||
// cd.curve->setYAxis(axis == 0 ? QwtPlot::yLeft : QwtPlot::yRight);
|
||||
// cd.curve->setSamples(cd.data);
|
||||
// curves[axis][t] = cd;
|
||||
// connect signals
|
||||
connect(t, &Trace::dataChanged, this, &TraceXYPlot::triggerReplot);
|
||||
connect(t, &Trace::colorChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
connect(t, &Trace::visibilityChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
// connect(t, &Trace::colorChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
// connect(t, &Trace::visibilityChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
connect(t, &Trace::visibilityChanged, this, &TraceXYPlot::triggerReplot);
|
||||
if(axis == 0) {
|
||||
connect(t, &Trace::markerAdded, this, &TraceXYPlot::markerAdded);
|
||||
@ -381,25 +663,25 @@ void TraceXYPlot::enableTraceAxis(Trace *t, int axis, bool enabled)
|
||||
if(isTDRtype(YAxis[axis].type)) {
|
||||
t->addTDRinterest();
|
||||
}
|
||||
traceColorChanged(t);
|
||||
// traceColorChanged(t);
|
||||
} else {
|
||||
if(isTDRtype(YAxis[axis].type)) {
|
||||
t->removeTDRinterest();
|
||||
}
|
||||
tracesAxis[axis].erase(t);
|
||||
// clean up and delete
|
||||
if(curves[axis].find(t) != curves[axis].end()) {
|
||||
delete curves[axis][t].curve;
|
||||
curves[axis].erase(t);
|
||||
}
|
||||
// if(curves[axis].find(t) != curves[axis].end()) {
|
||||
// delete curves[axis][t].curve;
|
||||
// curves[axis].erase(t);
|
||||
// }
|
||||
int otherAxis = axis == 0 ? 1 : 0;
|
||||
if(curves[otherAxis].find(t) == curves[otherAxis].end()) {
|
||||
// this trace is not used anymore, disconnect from notifications
|
||||
disconnect(t, &Trace::dataChanged, this, &TraceXYPlot::triggerReplot);
|
||||
disconnect(t, &Trace::colorChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
disconnect(t, &Trace::visibilityChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
disconnect(t, &Trace::visibilityChanged, this, &TraceXYPlot::triggerReplot);
|
||||
}
|
||||
// if(curves[otherAxis].find(t) == curves[otherAxis].end()) {
|
||||
// // this trace is not used anymore, disconnect from notifications
|
||||
// disconnect(t, &Trace::dataChanged, this, &TraceXYPlot::triggerReplot);
|
||||
// disconnect(t, &Trace::colorChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
// disconnect(t, &Trace::visibilityChanged, this, &TraceXYPlot::traceColorChanged);
|
||||
// disconnect(t, &Trace::visibilityChanged, this, &TraceXYPlot::triggerReplot);
|
||||
// }
|
||||
if(axis == 0) {
|
||||
disconnect(t, &Trace::markerAdded, this, &TraceXYPlot::markerAdded);
|
||||
disconnect(t, &Trace::markerRemoved, this, &TraceXYPlot::markerRemoved);
|
||||
@ -434,7 +716,7 @@ bool TraceXYPlot::supported(Trace *t, TraceXYPlot::YAxisType type)
|
||||
void TraceXYPlot::updateXAxis()
|
||||
{
|
||||
if(XAxis.mode == XAxisMode::Manual) {
|
||||
plot->setAxisScale(QwtPlot::xBottom, XAxis.rangeMin, XAxis.rangeMax, XAxis.rangeDiv);
|
||||
// plot->setAxisScale(QwtPlot::xBottom, XAxis.rangeMin, XAxis.rangeMax, XAxis.rangeDiv);
|
||||
} else {
|
||||
// automatic mode, figure out limits
|
||||
double max = std::numeric_limits<double>::lowest();
|
||||
@ -497,135 +779,151 @@ void TraceXYPlot::updateXAxis()
|
||||
for(double tick = start_div;tick <= max;tick += div_step) {
|
||||
tickList.append(tick);
|
||||
}
|
||||
QwtScaleDiv scalediv(min, max, QList<double>(), QList<double>(), tickList);
|
||||
plot->setAxisScaleDiv(QwtPlot::xBottom, scalediv);
|
||||
// QwtScaleDiv scalediv(min, max, QList<double>(), QList<double>(), tickList);
|
||||
// plot->setAxisScaleDiv(QwtPlot::xBottom, scalediv);
|
||||
}
|
||||
}
|
||||
|
||||
QwtSeriesData<QPointF> *TraceXYPlot::createQwtSeriesData(Trace &t, int axis)
|
||||
double TraceXYPlot::transformFrequencyY(std::complex<double> data, TraceXYPlot::YAxisType type)
|
||||
{
|
||||
return new QwtTraceSeries(t, YAxis[axis].type, this);
|
||||
}
|
||||
|
||||
void TraceXYPlot::traceColorChanged(Trace *t)
|
||||
{
|
||||
for(int axis = 0;axis < 2;axis++) {
|
||||
if(curves[axis].find(t) != curves[axis].end()) {
|
||||
// trace active, change the pen color
|
||||
if(t->isVisible()) {
|
||||
if(axis == 0) {
|
||||
curves[axis][t].curve->setPen(t->color());
|
||||
} else {
|
||||
curves[axis][t].curve->setPen(t->color(), 1.0, Qt::DashLine);
|
||||
}
|
||||
for(auto m : t->getMarkers()) {
|
||||
if(markers.count(m)) {
|
||||
markers[m]->attach(plot);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
curves[axis][t].curve->setPen(t->color(), 0.0, Qt::NoPen);
|
||||
for(auto m : t->getMarkers()) {
|
||||
if(markers.count(m)) {
|
||||
markers[m]->detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(type) {
|
||||
case YAxisType::Magnitude:
|
||||
return 20*log10(abs(data));
|
||||
case YAxisType::Phase:
|
||||
return arg(data) * 180.0 / M_PI;
|
||||
case YAxisType::VSWR:
|
||||
if(abs(data) < 1.0) {
|
||||
return (1+abs(data)) / (1-abs(data));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
void TraceXYPlot::markerAdded(TraceMarker *m)
|
||||
{
|
||||
if(markers.count(m)) {
|
||||
return;
|
||||
}
|
||||
auto qwtMarker = new QwtPlotMarker;
|
||||
markers[m] = qwtMarker;
|
||||
markerSymbolChanged(m);
|
||||
connect(m, &TraceMarker::symbolChanged, this, &TraceXYPlot::markerSymbolChanged);
|
||||
connect(m, &TraceMarker::dataChanged, this, &TraceXYPlot::markerDataChanged);
|
||||
markerDataChanged(m);
|
||||
qwtMarker->attach(plot);
|
||||
triggerReplot();
|
||||
}
|
||||
//QwtSeriesData<QPointF> *TraceXYPlot::createQwtSeriesData(Trace &t, int axis)
|
||||
//{
|
||||
// return new QwtTraceSeries(t, YAxis[axis].type, this);
|
||||
//}
|
||||
|
||||
void TraceXYPlot::markerRemoved(TraceMarker *m)
|
||||
{
|
||||
disconnect(m, &TraceMarker::symbolChanged, this, &TraceXYPlot::markerSymbolChanged);
|
||||
disconnect(m, &TraceMarker::dataChanged, this, &TraceXYPlot::markerDataChanged);
|
||||
if(markers.count(m)) {
|
||||
markers[m]->detach();
|
||||
delete markers[m];
|
||||
markers.erase(m);
|
||||
}
|
||||
triggerReplot();
|
||||
}
|
||||
//void TraceXYPlot::traceColorChanged(Trace *t)
|
||||
//{
|
||||
// for(int axis = 0;axis < 2;axis++) {
|
||||
// if(curves[axis].find(t) != curves[axis].end()) {
|
||||
// // trace active, change the pen color
|
||||
// if(t->isVisible()) {
|
||||
// if(axis == 0) {
|
||||
// curves[axis][t].curve->setPen(t->color());
|
||||
// } else {
|
||||
// curves[axis][t].curve->setPen(t->color(), 1.0, Qt::DashLine);
|
||||
// }
|
||||
// for(auto m : t->getMarkers()) {
|
||||
// if(markers.count(m)) {
|
||||
// markers[m]->attach(plot);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// curves[axis][t].curve->setPen(t->color(), 0.0, Qt::NoPen);
|
||||
// for(auto m : t->getMarkers()) {
|
||||
// if(markers.count(m)) {
|
||||
// markers[m]->detach();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
void TraceXYPlot::markerDataChanged(TraceMarker *m)
|
||||
{
|
||||
auto qwtMarker = markers[m];
|
||||
qwtMarker->setXValue(m->getFrequency());
|
||||
qwtMarker->setYValue(FrequencyAxisTransformation(YAxis[0].type, m->getData()));
|
||||
triggerReplot();
|
||||
}
|
||||
//void TraceXYPlot::markerAdded(TraceMarker *m)
|
||||
//{
|
||||
// if(markers.count(m)) {
|
||||
// return;
|
||||
// }
|
||||
// auto qwtMarker = new QwtPlotMarker;
|
||||
// markers[m] = qwtMarker;
|
||||
// markerSymbolChanged(m);
|
||||
// connect(m, &TraceMarker::symbolChanged, this, &TraceXYPlot::markerSymbolChanged);
|
||||
// connect(m, &TraceMarker::dataChanged, this, &TraceXYPlot::markerDataChanged);
|
||||
// markerDataChanged(m);
|
||||
// qwtMarker->attach(plot);
|
||||
// triggerReplot();
|
||||
//}
|
||||
|
||||
void TraceXYPlot::markerSymbolChanged(TraceMarker *m)
|
||||
{
|
||||
auto qwtMarker = markers[m];
|
||||
qwtMarker->setSymbol(nullptr);
|
||||
//void TraceXYPlot::markerRemoved(TraceMarker *m)
|
||||
//{
|
||||
// disconnect(m, &TraceMarker::symbolChanged, this, &TraceXYPlot::markerSymbolChanged);
|
||||
// disconnect(m, &TraceMarker::dataChanged, this, &TraceXYPlot::markerDataChanged);
|
||||
// if(markers.count(m)) {
|
||||
// markers[m]->detach();
|
||||
// delete markers[m];
|
||||
// markers.erase(m);
|
||||
// }
|
||||
// triggerReplot();
|
||||
//}
|
||||
|
||||
QwtSymbol *sym=new QwtSymbol;
|
||||
sym->setPixmap(m->getSymbol());
|
||||
sym->setPinPoint(QPointF(m->getSymbol().width()/2, m->getSymbol().height()));
|
||||
qwtMarker->setSymbol(sym);
|
||||
triggerReplot();
|
||||
}
|
||||
//void TraceXYPlot::markerDataChanged(TraceMarker *m)
|
||||
//{
|
||||
// auto qwtMarker = markers[m];
|
||||
// qwtMarker->setXValue(m->getFrequency());
|
||||
// qwtMarker->setYValue(FrequencyAxisTransformation(YAxis[0].type, m->getData()));
|
||||
// triggerReplot();
|
||||
//}
|
||||
|
||||
void TraceXYPlot::clicked(const QPointF pos)
|
||||
{
|
||||
auto clickPoint = drawPicker->plotToPixel(pos);
|
||||
unsigned int closestDistance = numeric_limits<unsigned int>::max();
|
||||
TraceMarker *closestMarker = nullptr;
|
||||
for(auto m : markers) {
|
||||
if(!m.first->isMovable()) {
|
||||
continue;
|
||||
}
|
||||
auto markerPoint = drawPicker->plotToPixel(m.second->value());
|
||||
auto yDiff = abs(markerPoint.y() - clickPoint.y());
|
||||
auto xDiff = abs(markerPoint.x() - clickPoint.x());
|
||||
unsigned int distance = xDiff * xDiff + yDiff * yDiff;
|
||||
if(distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
closestMarker = m.first;
|
||||
}
|
||||
}
|
||||
if(closestDistance <= 400) {
|
||||
selectedMarker = closestMarker;
|
||||
selectedCurve = curves[0][selectedMarker->trace()].curve;
|
||||
} else {
|
||||
selectedMarker = nullptr;
|
||||
selectedCurve = nullptr;
|
||||
}
|
||||
}
|
||||
//void TraceXYPlot::markerSymbolChanged(TraceMarker *m)
|
||||
//{
|
||||
// auto qwtMarker = markers[m];
|
||||
// qwtMarker->setSymbol(nullptr);
|
||||
|
||||
void TraceXYPlot::moved(const QPointF pos)
|
||||
{
|
||||
if(!selectedMarker || !selectedCurve) {
|
||||
return;
|
||||
}
|
||||
selectedMarker->setFrequency(pos.x());
|
||||
}
|
||||
// QwtSymbol *sym=new QwtSymbol;
|
||||
// sym->setPixmap(m->getSymbol());
|
||||
// sym->setPinPoint(QPointF(m->getSymbol().width()/2, m->getSymbol().height()));
|
||||
// qwtMarker->setSymbol(sym);
|
||||
// triggerReplot();
|
||||
//}
|
||||
|
||||
void TraceXYPlot::setColorFromPreferences()
|
||||
{
|
||||
auto pref = Preferences::getInstance();
|
||||
plot->setCanvasBackground(pref.General.graphColors.background);
|
||||
auto pal = plot->palette();
|
||||
pal.setColor(QPalette::Window, pref.General.graphColors.background);
|
||||
pal.setColor(QPalette::WindowText, pref.General.graphColors.axis);
|
||||
pal.setColor(QPalette::Text, pref.General.graphColors.axis);
|
||||
plot->setPalette(pal);
|
||||
grid->setPen(pref.General.graphColors.divisions);
|
||||
}
|
||||
//void TraceXYPlot::clicked(const QPointF pos)
|
||||
//{
|
||||
// auto clickPoint = drawPicker->plotToPixel(pos);
|
||||
// unsigned int closestDistance = numeric_limits<unsigned int>::max();
|
||||
// TraceMarker *closestMarker = nullptr;
|
||||
// for(auto m : markers) {
|
||||
// if(!m.first->isMovable()) {
|
||||
// continue;
|
||||
// }
|
||||
// auto markerPoint = drawPicker->plotToPixel(m.second->value());
|
||||
// auto yDiff = abs(markerPoint.y() - clickPoint.y());
|
||||
// auto xDiff = abs(markerPoint.x() - clickPoint.x());
|
||||
// unsigned int distance = xDiff * xDiff + yDiff * yDiff;
|
||||
// if(distance < closestDistance) {
|
||||
// closestDistance = distance;
|
||||
// closestMarker = m.first;
|
||||
// }
|
||||
// }
|
||||
// if(closestDistance <= 400) {
|
||||
// selectedMarker = closestMarker;
|
||||
// selectedCurve = curves[0][selectedMarker->trace()].curve;
|
||||
// } else {
|
||||
// selectedMarker = nullptr;
|
||||
// selectedCurve = nullptr;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void TraceXYPlot::moved(const QPointF pos)
|
||||
//{
|
||||
// if(!selectedMarker || !selectedCurve) {
|
||||
// return;
|
||||
// }
|
||||
// selectedMarker->setFrequency(pos.x());
|
||||
//}
|
||||
|
||||
//void TraceXYPlot::setColorFromPreferences()
|
||||
//{
|
||||
// auto pref = Preferences::getInstance();
|
||||
// plot->setCanvasBackground(pref.General.graphColors.background);
|
||||
// auto pal = plot->palette();
|
||||
// pal.setColor(QPalette::Window, pref.General.graphColors.background);
|
||||
// pal.setColor(QPalette::WindowText, pref.General.graphColors.axis);
|
||||
// pal.setColor(QPalette::Text, pref.General.graphColors.axis);
|
||||
// plot->setPalette(pal);
|
||||
// grid->setPen(pref.General.graphColors.divisions);
|
||||
//}
|
||||
|
||||
|
@ -3,31 +3,31 @@
|
||||
|
||||
#include "traceplot.h"
|
||||
#include <set>
|
||||
#include <qwt_plot.h>
|
||||
#include <qwt_plot_curve.h>
|
||||
#include <qwt_series_data.h>
|
||||
#include <qwt_plot_marker.h>
|
||||
#include <qwt_plot_grid.h>
|
||||
#include <qwt_plot_picker.h>
|
||||
//#include <qwt_plot.h>
|
||||
//#include <qwt_plot_curve.h>
|
||||
//#include <qwt_series_data.h>
|
||||
//#include <qwt_plot_marker.h>
|
||||
//#include <qwt_plot_grid.h>
|
||||
//#include <qwt_plot_picker.h>
|
||||
|
||||
// Derived plotpicker, exposing transformation functions
|
||||
class XYplotPicker : public QwtPlotPicker {
|
||||
Q_OBJECT
|
||||
public:
|
||||
XYplotPicker(int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QWidget *w)
|
||||
: QwtPlotPicker(xAxis, yAxis, rubberBand, trackerMode, w) {};
|
||||
QPoint plotToPixel(const QPointF &pos) {
|
||||
return transform(pos);
|
||||
}
|
||||
QPointF pixelToPlot(const QPoint &pos) {
|
||||
return invTransform(pos);
|
||||
}
|
||||
};
|
||||
//// Derived plotpicker, exposing transformation functions
|
||||
//class XYplotPicker : public QwtPlotPicker {
|
||||
// Q_OBJECT
|
||||
//public:
|
||||
// XYplotPicker(int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QWidget *w)
|
||||
// : QwtPlotPicker(xAxis, yAxis, rubberBand, trackerMode, w) {};
|
||||
// QPoint plotToPixel(const QPointF &pos) {
|
||||
// return transform(pos);
|
||||
// }
|
||||
// QPointF pixelToPlot(const QPoint &pos) {
|
||||
// return invTransform(pos);
|
||||
// }
|
||||
//};
|
||||
|
||||
class TraceXYPlot : public TracePlot
|
||||
{
|
||||
friend class XYplotAxisDialog;
|
||||
friend class QwtTraceSeries;
|
||||
// friend class QwtTraceSeries;
|
||||
Q_OBJECT
|
||||
public:
|
||||
TraceXYPlot(TraceModel &model, QWidget *parent = nullptr);
|
||||
@ -60,9 +60,10 @@ public:
|
||||
void setYAxis(int axis, YAxisType type, bool log, bool autorange, double min, double max, double div);
|
||||
void setXAxis(XAxisType type, XAxisMode mode, double min, double max, double div);
|
||||
void enableTrace(Trace *t, bool enabled) override;
|
||||
void updateSpan(double min, double max) override;
|
||||
|
||||
// Applies potentially changed colors to all XY-plots
|
||||
static void updateGraphColors();
|
||||
// static void updateGraphColors();
|
||||
bool isTDRtype(YAxisType type);
|
||||
|
||||
public slots:
|
||||
@ -71,24 +72,27 @@ public slots:
|
||||
protected:
|
||||
virtual void updateContextMenu() override;
|
||||
virtual bool supported(Trace *t) override;
|
||||
void replot() override;
|
||||
virtual void draw(QPainter &p) override;
|
||||
|
||||
private slots:
|
||||
void traceColorChanged(Trace *t);
|
||||
void markerAdded(TraceMarker *m) override;
|
||||
void markerRemoved(TraceMarker *m) override;
|
||||
void markerDataChanged(TraceMarker *m);
|
||||
void markerSymbolChanged(TraceMarker *m);
|
||||
void updateAxisTicks();
|
||||
// void traceColorChanged(Trace *t);
|
||||
// void markerAdded(TraceMarker *m) override;
|
||||
// void markerRemoved(TraceMarker *m) override;
|
||||
// void markerDataChanged(TraceMarker *m);
|
||||
// void markerSymbolChanged(TraceMarker *m);
|
||||
|
||||
void clicked(const QPointF pos);
|
||||
void moved(const QPointF pos);
|
||||
// void clicked(const QPointF pos);
|
||||
// void moved(const QPointF pos);
|
||||
private:
|
||||
void setColorFromPreferences();
|
||||
static constexpr int AxisLabelSize = 10;
|
||||
// void setColorFromPreferences();
|
||||
QString AxisTypeToName(YAxisType type);
|
||||
void enableTraceAxis(Trace *t, int axis, bool enabled);
|
||||
bool supported(Trace *t, YAxisType type);
|
||||
void updateXAxis();
|
||||
QwtSeriesData<QPointF> *createQwtSeriesData(Trace &t, int axis);
|
||||
double transformFrequencyY(std::complex<double> data, YAxisType type);
|
||||
// QwtSeriesData<QPointF> *createQwtSeriesData(Trace &t, int axis);
|
||||
|
||||
std::set<Trace*> tracesAxis[2];
|
||||
|
||||
@ -100,6 +104,7 @@ private:
|
||||
double rangeMin;
|
||||
double rangeMax;
|
||||
double rangeDiv;
|
||||
std::vector<double> ticks;
|
||||
};
|
||||
class XAxis {
|
||||
public:
|
||||
@ -109,27 +114,28 @@ private:
|
||||
double rangeMin;
|
||||
double rangeMax;
|
||||
double rangeDiv;
|
||||
std::vector<double> ticks;
|
||||
};
|
||||
|
||||
YAxis YAxis[2];
|
||||
XAxis XAxis;
|
||||
|
||||
using CurveData = struct {
|
||||
QwtPlotCurve *curve;
|
||||
QwtSeriesData<QPointF> *data;
|
||||
};
|
||||
// using CurveData = struct {
|
||||
// QwtPlotCurve *curve;
|
||||
// QwtSeriesData<QPointF> *data;
|
||||
// };
|
||||
|
||||
std::map<Trace*, CurveData> curves[2];
|
||||
std::map<TraceMarker*, QwtPlotMarker*> markers;
|
||||
QwtPlot *plot;
|
||||
QwtPlotGrid *grid;
|
||||
// std::map<Trace*, CurveData> curves[2];
|
||||
// std::map<TraceMarker*, QwtPlotMarker*> markers;
|
||||
// QwtPlot *plot;
|
||||
// QwtPlotGrid *grid;
|
||||
TraceMarker *selectedMarker;
|
||||
QwtPlotCurve *selectedCurve;
|
||||
// QwtPlotCurve *selectedCurve;
|
||||
|
||||
XYplotPicker *drawPicker;
|
||||
// XYplotPicker *drawPicker;
|
||||
|
||||
// keep track of all created plots for changing colors
|
||||
static std::set<TraceXYPlot*> allPlots;
|
||||
// static std::set<TraceXYPlot*> allPlots;
|
||||
};
|
||||
|
||||
#endif // TRACEXYPLOT_H
|
||||
|
@ -2,6 +2,9 @@
|
||||
<ui version="4.0">
|
||||
<class>XYplotAxisDialog</class>
|
||||
<widget class="QDialog" name="XYplotAxisDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@ -547,7 +550,7 @@
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="Y2group"/>
|
||||
<buttongroup name="Y1group"/>
|
||||
<buttongroup name="Y2group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
13
Software/PC_Application/Util/util.h
Normal file
13
Software/PC_Application/Util/util.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef UTILH_H
|
||||
#define UTILH_H
|
||||
|
||||
namespace Util {
|
||||
template<typename T> T Scale(T value, T from_low, T from_high, T to_low, T to_high) {
|
||||
value -= from_low;
|
||||
value *= (to_high - to_low) / (from_high - from_low);
|
||||
value += to_low;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UTILH_H
|
@ -43,6 +43,7 @@
|
||||
#include <QActionGroup>
|
||||
#include <QErrorMessage>
|
||||
#include "CustomWidgets/informationbox.h"
|
||||
#include <QDebug>
|
||||
|
||||
VNA::VNA(AppWindow *window)
|
||||
: Mode(window, "Vector Network Analyzer"),
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "SpectrumAnalyzer/spectrumanalyzer.h"
|
||||
#include "Calibration/sourcecaldialog.h"
|
||||
#include "Calibration/receivercaldialog.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -107,7 +108,7 @@ AppWindow::AppWindow(QWidget *parent)
|
||||
connect(ui->actionPreferences, &QAction::triggered, [=](){
|
||||
Preferences::getInstance().edit();
|
||||
// settings might have changed, update necessary stuff
|
||||
TraceXYPlot::updateGraphColors();
|
||||
// TraceXYPlot::updateGraphColors();
|
||||
});
|
||||
connect(ui->actionAbout, &QAction::triggered, [=](){
|
||||
auto commit = QString(GITHASH);
|
||||
|
@ -3,12 +3,11 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
class Unit
|
||||
namespace Unit
|
||||
{
|
||||
public:
|
||||
static double FromString(QString string, QString unit = QString(), QString prefixes = " ");
|
||||
static QString ToString(double value, QString unit = QString(), QString prefixes = " ", int precision = 6);
|
||||
static double SIPrefixToFactor(char prefix);
|
||||
double FromString(QString string, QString unit = QString(), QString prefixes = " ");
|
||||
QString ToString(double value, QString unit = QString(), QString prefixes = " ", int precision = 6);
|
||||
double SIPrefixToFactor(char prefix);
|
||||
};
|
||||
|
||||
#endif // UNIT_H
|
||||
|
Loading…
Reference in New Issue
Block a user