#include "graphic_analysis.h" #include "graphic_analysis_stat.h" #include "qad_types.h" #include "ui_graphic_analysis.h" #include #include PIVector getAmplitude(const PIVector & result) { PIVector ret; ret.resize(result.size()); double tmp; for (uint i = 0; i < result.size(); i++) { tmp = sqrt(result[i].real() * result[i].real() + result[i].imag() * result[i].imag()); ret[i] = tmp; } return ret; } PIVector spectrumPIVector(PIFFTWd & fft, const PIVector & in, double frequency, QPointF * fft_mul = nullptr) { PIVector ret; if (in.size() <= 2 || frequency <= 0.) return ret; ret = getAmplitude(fft.calcFFT(in)); ret.resize(ret.size_s() / 2); ret[0] = 0.; if (fft_mul) *fft_mul = QPointF(frequency / ret.size_s() / 2., 1. / ret.size_s()); return ret; } QPolygonF spectrumQPolygonF(PIFFTWd & fft, const PIVector & in, double frequency, QPointF * fft_mul = nullptr) { QPolygonF ret; QPointF mul; PIVector spec = spectrumPIVector(fft, in, frequency, &mul); if (spec.isEmpty()) return ret; ret.resize(spec.size_s()); for (int i = 0; i < ret.size(); ++i) ret[i] = QPointF(i * mul.x(), spec[i] * mul.y()); if (fft_mul) *fft_mul = mul; return ret; } // GraphicAnalysis PRIVATE_DEFINITION_START(GraphicAnalysis) PIFFTWd fft; PRIVATE_DEFINITION_END(GraphicAnalysis) GraphicAnalysis::GraphicAnalysis(QWidget * parent): GraphicRanges(parent) { widget_toolbox = new QWidget(); ui = new Ui::GraphicAnalysis(); ui->setupUi(widget_toolbox); ui->widgetSpectrum->hide(); window_stat = new GraphicAnalysisStatistics(); connect(ui->checkSpectrum, SIGNAL(toggled(bool)), this, SLOT(checkSpectrum_toggled(bool))); connect(ui->buttonSpectrumRange, SIGNAL(toggled(bool)), this, SLOT(buttonSpectrumRange_toggled(bool))); connect(ui->checkSpectrumFixDuration, SIGNAL(toggled(bool)), this, SLOT(checkSpectrumFixDuration_toggled(bool))); connect(ui->buttonStatistics, SIGNAL(toggled(bool)), this, SLOT(buttonStatistics_toggled(bool))); auto * lay = qobject_cast(layout()); lay->insertWidget(0, widget_toolbox); connect(ui->spinSpectrumDuration, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged())); connect(this, SIGNAL(rangeSelected(double, double)), this, SLOT(gaRangeSelected(double, double))); connect(this, SIGNAL(graphicMousePressEvent(QPointF, int)), this, SLOT(gaMousePressEvent(QPointF, int))); connect(this, SIGNAL(graphicMouseMoveEvent(QPointF, int)), this, SLOT(gaMouseMoveEvent(QPointF, int))); connect(this, SIGNAL(graphicMouseReleaseEvent(QPointF, int)), this, SLOT(gaMouseReleaseEvent(QPointF, int))); } GraphicAnalysis::~GraphicAnalysis() { delete window_stat; delete ui; } void GraphicAnalysis::setGraphicData(const QPolygonF & g, int graphic, bool update_) { if (graphic < 0 || graphic >= graphicsCount()) return; src_data[graphic] = g; updateGraphic(graphic); if (update_) viewport()->update(); } bool GraphicAnalysis::isSpectrumFixedDuration() const { return ui->checkSpectrumFixDuration->isChecked(); } void GraphicAnalysis::setIsSpectrumFixedDuration(bool on) { ui->checkSpectrumFixDuration->setChecked(on); } double GraphicAnalysis::spectrumFixedDuration() const { return ui->spinSpectrumDuration->value(); } void GraphicAnalysis::setSpectrumFixedDuration(double val) { ui->spinSpectrumDuration->setValue(val); } bool GraphicAnalysis::isToolboxVisible() const { return widget_toolbox->isVisible(); } void GraphicAnalysis::setToolboxVisible(bool yes) { widget_toolbox->setVisible(yes); } void GraphicAnalysis::setLabelX(const QString & str) { data_label_x = str; if (!show_fft) Graphic::setLabelX(str); } QWidget * GraphicAnalysis::toolboxWidget() { return widget_toolbox; } void GraphicAnalysis::setShowSpectrum(bool on) { ui->checkSpectrum->setChecked(on); } bool GraphicAnalysis::isShowSpectrum() const { return show_fft; } void GraphicAnalysis::changeEvent(QEvent * e) { Graphic::changeEvent(e); if (e->type() == QEvent::LanguageChange) { ui->retranslateUi(this); return; } } void GraphicAnalysis::updateGraphic(int index) { if (!show_fft) { if (tf_gr) Graphic::setGraphicData(tf_gr(src_data.value(index)), index, false); else Graphic::setGraphicData(src_data.value(index), index, false); } else { const QPolygonF & src(src_data[index]); int si = 0, ei = src.size() - 1; for (int i = 0; i < src.size(); ++i) { if (src[i].x() >= range_fft.start) { si = i; break; } } for (int i = si; i < src.size(); ++i) { if (src[i].x() > range_fft.end) { ei = i; break; } } if (ei - si < 4) { Graphic::setGraphicData({}, index, false); return; } if (tf_fft) Graphic::setGraphicData(tf_fft(calcToFFT(&(src[si]), ei - si)), index, false); else Graphic::setGraphicData(calcToFFT(&(src[si]), ei - si), index, false); } } void GraphicAnalysis::updateAllGraphic() { for (int i = 0; i < graphicsCount(); ++i) updateGraphic(i); updateGraphics(); } void GraphicAnalysis::setFFT(bool on) { if (show_fft) { setFFTInternal(false); } if (on) { range_fft = rangeVisible(); setFFTInternal(true); } } void GraphicAnalysis::setFFTInternal(bool on) { bool need_autofit = false; if (!show_fft && on) { saved_view = visualRect(); saved_autofit = isAutofitted(); need_autofit = true; } if (show_fft && !on) { setVisualRect(saved_view); if (saved_autofit) need_autofit = true; } show_fft = on; Graphic::setLabelX(on ? tr("Hz") : data_label_x); emit showSpectrumChanged(show_fft); updateAllGraphic(); if (need_autofit) { autofit(); } } QPolygonF GraphicAnalysis::calcToFFT(const QPointF * in, int count) { PIVector fft_in, fft_out; fft_in.reserve(count); for (int i = 0; i < count; ++i) fft_in << in[i].y(); double freq = double(count - 1) / (in[count - 1].x() - in[0].x()); return spectrumQPolygonF(PRIVATE->fft, fft_in, freq); } void GraphicAnalysis::checkRangeRequest() { if (!ui->buttonSpectrumRange->isChecked()) return; viewport()->unsetCursor(); if (!ui->checkSpectrumFixDuration->isChecked()) { rangeRequest(); } else { cancelRangeRequest(false); viewport()->setCursor(Qt::CrossCursor); } } void GraphicAnalysis::clear() { src_data.clear(); Graphic::clear(); } void GraphicAnalysis::setGraphicsCount(int cnt, bool update) { for (int i = cnt; i < graphicsCount(); ++i) src_data.remove(i); Graphic::setGraphicsCount(cnt, update); } void GraphicAnalysis::addPoint(const QPointF & p, int graphic, bool update_) { src_data[graphic] << p; if (show_fft) return; Graphic::addPoint(p, graphic, update_); } void GraphicAnalysis::setGraphicTransformFunction(std::function f) { tf_gr = f; updateAllGraphic(); } void GraphicAnalysis::setSpectrumTransformFunction(std::function f) { tf_fft = f; updateAllGraphic(); } void GraphicAnalysis::gaMousePressEvent(QPointF point, int buttons) { if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return; setNavigationEnabled(false); graphicMouseMoveEvent(point, buttons); } void GraphicAnalysis::gaMouseMoveEvent(QPointF point, int buttons) { if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return; setCurrentRange(point.x(), point.x() + ui->spinSpectrumDuration->value()); } void GraphicAnalysis::gaMouseReleaseEvent(QPointF point, int buttons) { if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return; auto r = currentRange(); clearCurrentRange(); gaRangeSelected(r.start, r.end); viewport()->setCursor(Qt::ArrowCursor); QTimer::singleShot(10, [this]() { setNavigationEnabled(true); update(); }); } void GraphicAnalysis::gaRangeSelected(double start, double end) { if (ui->buttonSpectrumRange->isChecked()) { ui->buttonSpectrumRange->setChecked(false); range_fft = GraphicRanges::Range(start, end); updateAllGraphic(); } if (ui->buttonStatistics->isChecked()) { ui->buttonStatistics->setChecked(false); window_stat->show(this, GraphicRanges::Range(start, end)); } } void GraphicAnalysis::checkSpectrum_toggled(bool on) { if (!on) ui->buttonSpectrumRange->setChecked(false); setFFT(on); } void GraphicAnalysis::buttonSpectrumRange_toggled(bool on) { setFFT(!on); if (on) { ui->buttonStatistics->setChecked(false); checkRangeRequest(); } else viewport()->unsetCursor(); } void GraphicAnalysis::checkSpectrumFixDuration_toggled(bool on) { checkRangeRequest(); emit configChanged(); } void GraphicAnalysis::buttonStatistics_toggled(bool on) { if (on) { ui->buttonSpectrumRange->setChecked(false); rangeRequest(); } else viewport()->unsetCursor(); }