diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b502d9..51ef492 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default project(QAD) set(QAD_MAJOR 2) -set(QAD_MINOR 17) +set(QAD_MINOR 18) set(QAD_REVISION 0) set(QAD_SUFFIX ) set(QAD_COMPANY SHS) diff --git a/cmake/FindQAD.cmake b/cmake/FindQAD.cmake index 512d34c..e9e3a1d 100644 --- a/cmake/FindQAD.cmake +++ b/cmake/FindQAD.cmake @@ -6,6 +6,7 @@ Create imported targets: * QAD::Application * QAD::Blockview * QAD::Graphic + * QAD::GraphicAnalysis * QAD::SQLTable * QAD::TouchWidgets * QAD::Doc @@ -44,23 +45,24 @@ if(QAD_FIND_VERSION VERSION_GREATER QAD_VERSION) message(FATAL_ERROR "QAD version ${QAD_VERSION} is available, but ${QAD_FIND_VERSION} requested!") endif() -set(__libs "utils;widgets;application;blockview;graphic;sql;sql_table;touch_widgets;doc;map") +set(__libs "utils;widgets;application;blockview;graphic;graphic_analysis;sql;sql_table;touch_widgets;doc;map") if (PIP_FOUND OR BUILDING_PIP) list(APPEND __libs "piqt;piqt_utils") endif() -set(__module_utils Utils ) -set(__module_widgets Widgets ) -set(__module_application Application ) -set(__module_blockview Blockview ) -set(__module_graphic Graphic ) -set(__module_sql SQL ) -set(__module_sql_table SQLTable ) -set(__module_touch_widgets TouchWidgets ) -set(__module_doc Doc ) -set(__module_map Map ) -set(__module_piqt PIQt ) -set(__module_piqt_utils PIQtUtils ) +set(__module_utils Utils ) +set(__module_widgets Widgets ) +set(__module_application Application ) +set(__module_blockview Blockview ) +set(__module_graphic Graphic ) +set(__module_graphic_analysis GraphicAnalysis) +set(__module_sql SQL ) +set(__module_sql_table SQLTable ) +set(__module_touch_widgets TouchWidgets ) +set(__module_doc Doc ) +set(__module_map Map ) +set(__module_piqt PIQt ) +set(__module_piqt_utils PIQtUtils ) foreach (_l ${__libs}) set( __inc_${_l} "") @@ -68,15 +70,16 @@ foreach (_l ${__libs}) set(__libs_${_l} "") endforeach() -set(__deps_widgets "QAD::Utils") -set(__deps_application "QAD::Widgets") -set(__deps_blockview "QAD::Widgets") -set(__deps_graphic "QAD::Widgets") -set(__deps_sql "QAD::Utils") -set(__deps_sql_table "QAD::Widgets") -set(__deps_map "QAD::Utils;QAD::PIQt") -set(__deps_piqt "QAD::Widgets;PIP") -set(__deps_piqt_utils "QAD::Blockview;QAD::PIQt") +set(__deps_widgets "QAD::Utils") +set(__deps_application "QAD::Widgets") +set(__deps_blockview "QAD::Widgets") +set(__deps_graphic "QAD::Widgets") +set(__deps_graphic_analysis "QAD::Graphic;PIP::FFTW") +set(__deps_sql "QAD::Utils") +set(__deps_sql_table "QAD::Widgets") +set(__deps_map "QAD::Utils;QAD::PIQt") +set(__deps_piqt "QAD::Widgets;PIP") +set(__deps_piqt_utils "QAD::Blockview;QAD::PIQt") #message("find QAD ${BUILDING_QAD}") diff --git a/cmake/QtWraps.cmake b/cmake/QtWraps.cmake index 89a68dc..9ecc10d 100644 --- a/cmake/QtWraps.cmake +++ b/cmake/QtWraps.cmake @@ -926,6 +926,15 @@ macro(qad_install_lang _NAME) if ("${_libname}" STREQUAL "qad_piqtutils") set(_libname "qad_piqt_utils") endif() + if ("${_libname}" STREQUAL "qad_sqltable") + set(_libname "qad_sql_table") + endif() + if ("${_libname}" STREQUAL "qad_touchwidgets") + set(_libname "qad_touch_widgets") + endif() + if ("${_libname}" STREQUAL "qad_graphicanalysis") + set(_libname "qad_graphic_analysis") + endif() #message("imp lib \"${_libname}\"") list(APPEND _qt_libs ${_libname}) endif() diff --git a/libs/graphic/graphic.cpp b/libs/graphic/graphic.cpp index 8ee8b3d..b059f03 100644 --- a/libs/graphic/graphic.cpp +++ b/libs/graphic/graphic.cpp @@ -209,7 +209,7 @@ Graphic::~Graphic() { delete buttons_menu; #endif delete conf; - // if (buffer != 0) delete buffer; + delete ui; } diff --git a/libs/graphic/graphic.ui b/libs/graphic/graphic.ui index 3c30c7e..43c7399 100644 --- a/libs/graphic/graphic.ui +++ b/libs/graphic/graphic.ui @@ -16,7 +16,10 @@ 150 - + + + 0 + 0 @@ -29,384 +32,388 @@ 0 - - 2 - - - - - Qt::RichText + + + + 2 - - Qt::AlignCenter - - - - - - - - - -10 - 0 - 35 - 420 - - - - - 2 - - - - - Autofit - - - - :/icons/view-autofit.png:/icons/view-autofit.png - - - - - - - Cursor axis - - - - :/icons/edit-guides.png:/icons/edit-guides.png - - - true - - - - - - - Fullscreen - - - - :/icons/view-fullscreen.png:/icons/view-fullscreen.png - - - - - - - Border inputs - - - - :/icons/border-line.png:/icons/border-line.png - - - true - - - - - - - Legend - - - - :/icons/legend.png:/icons/legend.png - - - true - - - false - - - - - - - Pause - - - - :/icons/media-playback-pause.png:/icons/media-playback-pause.png - - - true - - - - - - - Configure ... - - - - :/icons/configure.png:/icons/configure.png - - - - - - - Save image ... - - - - :/icons/document-save.png:/icons/document-save.png - - - QToolButton::InstantPopup - - - - - - - Record graphic - - - - :/icons/media-record.png:/icons/media-record.png - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 0 - 30 - - - - - - - - Clear - - - - :/icons/edit-clear.png:/icons/edit-clear.png - - - - - - - Close - - - - :/icons/dialog-close.png:/icons/dialog-close.png - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - - - - - - Cursor: ( ; ) - - - - - - - - 0 - 0 - - - - QFrame::Box - - - QFrame::Sunken - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - + + + + + + -10 + 0 + 35 + 420 + - + - 0 - - - 2 - - - 2 - - - 2 - - 2 - + + + Autofit + + + + :/icons/view-autofit.png:/icons/view-autofit.png + + + + + + + Cursor axis + + + + :/icons/edit-guides.png:/icons/edit-guides.png + + + true + + + + + + + Fullscreen + + + + :/icons/view-fullscreen.png:/icons/view-fullscreen.png + + + + + + + Border inputs + + + + :/icons/border-line.png:/icons/border-line.png + + + true + + + + + + + Legend + + + + :/icons/legend.png:/icons/legend.png + + + true + + + false + + + + + + + Pause + + + + :/icons/media-playback-pause.png:/icons/media-playback-pause.png + + + true + + + + + + + Configure ... + + + + :/icons/configure.png:/icons/configure.png + + + + + + + Save image ... + + + + :/icons/document-save.png:/icons/document-save.png + + + QToolButton::InstantPopup + + + + + + + Record graphic + + + + :/icons/media-record.png:/icons/media-record.png + + + true + + + + + - Qt::Horizontal + Qt::Vertical + + + QSizePolicy::Preferred - 40 - 20 + 0 + 30 - - - - - - - 0 - - - - - true - - - - - - - - - - 0 - 0 - - - - - 0 - - - 2 - - - 2 - - - 2 - - - 2 - - + + + Clear + + + + :/icons/edit-clear.png:/icons/edit-clear.png + + + + + + + Close + + + + :/icons/dialog-close.png:/icons/dialog-close.png + + + + + Qt::Vertical - 20 - 40 + 0 + 0 - - - - - - 1 - - - 1 - - - 1 - - - 1 - - - 4 - - - 2 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - + + + + + + Qt::RichText + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + + + true + + + + + + + + + + 0 + 0 + + + + + 0 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 1 + + + 1 + + + 1 + + + 1 + + + 4 + + + 2 + + + + + + + + + + + Cursor: ( ; ) + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + diff --git a/libs/graphic/graphic_ranges.cpp b/libs/graphic/graphic_ranges.cpp new file mode 100644 index 0000000..01c1fd6 --- /dev/null +++ b/libs/graphic/graphic_ranges.cpp @@ -0,0 +1,184 @@ +#include +#include "graphic_ranges.h" + + +GraphicRanges::GraphicRanges(QWidget * parent): Graphic(parent) { + connect(this, SIGNAL(graphicPaintEvent(QPainter *)), this, SLOT(onPaintEvent(QPainter *))); + connect(this, SIGNAL(graphicMousePressEvent(QPointF, int)), this, SLOT(onMousePressEvent(QPointF, int))); + connect(this, SIGNAL(graphicMouseMoveEvent(QPointF, int)), this, SLOT(onMouseMoveEvent(QPointF, int))); + connect(this, SIGNAL(graphicMouseReleaseEvent(QPointF, int)), this, SLOT(onMouseReleaseEvent(QPointF, int))); + //setOpenGL(true); + range_start = range_end = 0.; + range_sel = request = false; + color_ = QColor(64, 192, 64, 128); + color_cur = QColor(64, 64, 192, 128); +} + + +GraphicRanges::~GraphicRanges() { +} + + +int GraphicRanges::addRange(double start, double end, QString name, QColor color) { + ranges_ << Range(start, end, name, color); + update(); + return ranges_.size() - 1; +} + + +void GraphicRanges::replaceRange(int index, double start, double end) { + if (index < 0 || index >= ranges_.size()) return; + ranges_[index].start = start; + ranges_[index].end = end; + update(); +} + + +GraphicRanges::Range GraphicRanges::removeRange(int index) { + if (index < 0 || index >= ranges_.size()) return Range(); + Range ret = ranges_.takeAt(index); + update(); + return ret; +} + + +void GraphicRanges::clearRanges() { + ranges_.clear(); + update(); +} + + +void GraphicRanges::clearRangesByColor(QColor c) { + for (int i = 0; i < ranges_.size(); ++i) { + if (ranges_[i].color == c) { + ranges_.removeAt(i); + --i; + } + } + update(); +} + + +GraphicRanges::Range GraphicRanges::rangeAll() const { + Range ret; + for (int g = 0; g < graphicsCount(); ++g) { + const QPolygonF & gd(graphics[g].polyline); + if (!gd.isEmpty()) { + if (ret.isEmpty()) { + ret.start = gd.front().x(); + ret.end = gd.back ().x(); + } else { + ret.start = qMin(ret.start, gd.front().x()); + ret.end = qMax(ret.end , gd.back ().x()); + } + } + } + return ret; +} + + +GraphicRanges::Range GraphicRanges::rangeVisible() const { + Range ret; + ret.start = visualRect().left (); + ret.end = visualRect().right(); + return ret; +} + + +void GraphicRanges::setCurrentRange(double start, double end) { + range_start = start; + range_end = end; + update(); +} + + +void GraphicRanges::clearCurrentRange() { + range_start = range_end = 0.; + update(); +} + + +GraphicRanges::Range GraphicRanges::currentRange() const { + return Range(range_start, range_end); +} + + +void GraphicRanges::clear() { + ranges_.clear(); + Graphic::clear(); +} + + +void GraphicRanges::drawRange(QPainter * p, const GraphicRanges::Range & r, QColor color) { + if (r.isEmpty()) return; + double cx[2] = {real2canvasX(r.start), + real2canvasX(r.end)}; + p->fillRect(QRectF(cx[0], 0, cx[1] - cx[0], height()), color); + p->setPen(QPen(QColor(color.rgb()), 2, Qt::DotLine)); + p->drawLine(cx[0], 0, cx[0], height()); + p->drawLine(cx[1], 0, cx[1], height()); + if (!r.name.isEmpty()) { + p->setPen(QPen(QColor(color.rgb()).darker(), 1, Qt::SolidLine)); + p->drawText(QRectF(cx[0], 10, cx[1] - cx[0], height() - 10), Qt::AlignHCenter | Qt::AlignTop | Qt::TextDontClip, r.name); + } + +} + + +void GraphicRanges::onPaintEvent(QPainter * p) { + p->save(); + //QPen pen = p->pen(); + for (const auto & r: ranges_) { + drawRange(p, r, r.hasColor() ? r.color : color_); + } + drawRange(p, Range(range_start, range_end), color_cur); + p->restore(); +} + + +void GraphicRanges::onMousePressEvent(QPointF p, int b) { + if (b == Qt::RightButton) return;// request = false; + if (b != Qt::LeftButton || !request) return; + update(); + range_sel = true; + range_start = range_end = p.x(); + setNavigationEnabled(false); +} + + +void GraphicRanges::onMouseMoveEvent(QPointF p, int b) { + if (!range_sel) return; + range_end = p.x(); + update(); +} + + +void GraphicRanges::onMouseReleaseEvent(QPointF p, int b) { + if (b == Qt::RightButton && range_sel) + canvas->setCursor(Qt::SplitHCursor); + if (b != Qt::LeftButton) return; + if (range_sel) { + range_sel = request = false; + range_end = p.x(); + if (range_start > range_end) + std::swap(range_start, range_end); + rangeSelected(range_start, range_end); + canvas->setCursor(Qt::ArrowCursor); + range_start = range_end = 0.; + } + QTimer::singleShot(10, [this](){setNavigationEnabled(true); update();}); +} + + +void GraphicRanges::rangeRequest() { + request = true; + canvas->setCursor(Qt::SplitHCursor); +} + + +void GraphicRanges::cancelRangeRequest(bool with_nav) { + request = false; + canvas->setCursor(Qt::ArrowCursor); + if (with_nav) + QTimer::singleShot(10, [this](){setNavigationEnabled(true); update();}); +} diff --git a/libs/graphic/graphic_ranges.h b/libs/graphic/graphic_ranges.h new file mode 100644 index 0000000..9db55fa --- /dev/null +++ b/libs/graphic/graphic_ranges.h @@ -0,0 +1,87 @@ +/* + QAD - Qt ADvanced + + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef GRAPHIC_RANGES_H +#define GRAPHIC_RANGES_H + +#include "graphic.h" + + +class QAD_GRAPHIC_EXPORT GraphicRanges: public Graphic { + Q_OBJECT + +public: + explicit GraphicRanges(QWidget * parent = 0); + ~GraphicRanges(); + + struct QAD_GRAPHIC_EXPORT Range { + Range(double s = 0., double e = 0., QString n = QString(), QColor c = Qt::black) { + start = s; + end = e; + name = n; + color = c; + } + bool isEmpty() const { return qFuzzyIsNull(start - end); } + bool hasColor() const { return color != Qt::black; } + QString name; + QColor color; + double start; + double end; + }; + + int addRange(double start, double end, QString name, QColor color = Qt::black); + void replaceRange(int index, double start, double end); + Range removeRange(int index); + void clearRanges(); + void clearRangesByColor(QColor c); + QList ranges() const { return ranges_; } + Range rangeAll() const; + Range rangeVisible() const; + bool isRangeRequested() const { return request; } + + void setCurrentRange(double start, double end); + void clearCurrentRange(); + Range currentRange() const; + + void clear(); + +protected: + void drawRange(QPainter * p, const Range & r, QColor color); + + QList ranges_; + QColor color_, color_cur; + double range_start, range_end; + bool range_sel, request; + +private slots: + void onPaintEvent(QPainter * p); + void onMousePressEvent(QPointF p, int b); + void onMouseMoveEvent(QPointF p, int b); + void onMouseReleaseEvent(QPointF p, int b); + +public slots: + void rangeRequest(); + void cancelRangeRequest(bool with_nav = true); + +signals: + void rangeSelected(double start, double end); +}; + + +#endif diff --git a/libs/graphic/plugin/graphicplugin.cpp b/libs/graphic/plugin/graphicplugin.cpp index 707f984..e6b1dee 100644 --- a/libs/graphic/plugin/graphicplugin.cpp +++ b/libs/graphic/plugin/graphicplugin.cpp @@ -2,7 +2,7 @@ #include "graphic.h" -#include +#include GraphicPlugin::GraphicPlugin(QObject * parent): QObject(parent) { @@ -10,12 +10,9 @@ GraphicPlugin::GraphicPlugin(QObject * parent): QObject(parent) { } -void GraphicPlugin::initialize(QDesignerFormEditorInterface * /* core */) { +void GraphicPlugin::initialize(QDesignerFormEditorInterface *) { m_designer = true; if (m_initialized) return; - - // Add extension registrations, etc. here - m_initialized = true; } diff --git a/libs/graphic/plugin/qad_graphic.cpp b/libs/graphic/plugin/qad_graphic.cpp index 344842c..f15896f 100644 --- a/libs/graphic/plugin/qad_graphic.cpp +++ b/libs/graphic/plugin/qad_graphic.cpp @@ -3,7 +3,7 @@ #include "graphicplugin.h" QADGraphic::QADGraphic(QObject * parent): QObject(parent) { - m_widgets.append(new GraphicPlugin(this)); + m_widgets << new GraphicPlugin(this); } diff --git a/libs/graphic_analysis/CMakeLists.txt b/libs/graphic_analysis/CMakeLists.txt new file mode 100644 index 0000000..f0f5865 --- /dev/null +++ b/libs/graphic_analysis/CMakeLists.txt @@ -0,0 +1,6 @@ +find_package(PIP) +if (PIP_FOUND) + + qad_library(graphic_analysis "Gui;Positioning" "PIP::FFTW;qad_graphic") + +endif() diff --git a/libs/graphic_analysis/graphic_analysis.cpp b/libs/graphic_analysis/graphic_analysis.cpp new file mode 100644 index 0000000..8bc4609 --- /dev/null +++ b/libs/graphic_analysis/graphic_analysis.cpp @@ -0,0 +1,321 @@ +#include "graphic_analysis.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(); + 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))); + 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 ui; + delete widget_toolbox; +} + + +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); +} + + +QBoxLayout * GraphicAnalysis::toolboxLayout() { + return reinterpret_cast(widget_toolbox->layout()); +} + + +QWidget * GraphicAnalysis::toolboxWidget() { + return widget_toolbox; +} + + +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); +} + + +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; +} + + +void GraphicAnalysis::setSpectrumTransformFunction(std::function f) { + tf_fft = f; +} + + +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()) return; + ui->buttonSpectrumRange->setChecked(false); + range_fft = GraphicRanges::Range(start, end); + updateAllGraphic(); +} + + +void GraphicAnalysis::checkSpectrum_toggled(bool on) { + if (!on) ui->buttonSpectrumRange->setChecked(false); + setFFT(on); +} + + +void GraphicAnalysis::buttonSpectrumRange_toggled(bool on) { + setFFT(!on); + if (on) + checkRangeRequest(); + else + viewport()->unsetCursor(); +} + + +void GraphicAnalysis::checkSpectrumFixDuration_toggled(bool on) { + checkRangeRequest(); + emit configChanged(); +} diff --git a/libs/graphic_analysis/graphic_analysis.h b/libs/graphic_analysis/graphic_analysis.h new file mode 100644 index 0000000..eda7344 --- /dev/null +++ b/libs/graphic_analysis/graphic_analysis.h @@ -0,0 +1,101 @@ +/* + QAD - Qt ADvanced + + Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef graphic_analysis_h +#define graphic_analysis_h + +#include "qad_graphic_analysis_export.h" + +#include +#include + +namespace Ui { +class GraphicAnalysis; +} +class GraphicAnalysisPlugin; + +class QAD_GRAPHIC_ANALYSIS_EXPORT GraphicAnalysis: public GraphicRanges { + Q_OBJECT + friend class GraphicAnalysisPlugin; + Q_PROPERTY(bool toolboxVisible READ isToolboxVisible WRITE setToolboxVisible) + +public: + GraphicAnalysis(QWidget * parent = 0); + virtual ~GraphicAnalysis(); + + void setGraphicData(const QPolygonF & g, int graphic, bool update_ = true); + + bool isSpectrumFixedDuration() const; + void setIsSpectrumFixedDuration(bool on); + double spectrumFixedDuration() const; + void setSpectrumFixedDuration(double val); + + bool isToolboxVisible() const; + void setToolboxVisible(bool yes); + void setLabelX(const QString & str); + QBoxLayout * toolboxLayout(); + QWidget * toolboxWidget(); + bool isShowSpectrum() const; + + void setGraphicsCount(int cnt, bool update = true); + void addPoint(const QPointF & p, int graphic, bool update_ = true); + + void setGraphicTransformFunction(std::function f); + void setSpectrumTransformFunction(std::function f); + +protected: + void changeEvent(QEvent * e); + + void updateGraphic(int index); + void updateAllGraphic(); + void setFFTInternal(bool on); + void setFFT(bool on); + QPolygonF calcToFFT(const QPointF * in, int count); + void checkRangeRequest(); + + Ui::GraphicAnalysis * ui = nullptr; + QWidget * widget_toolbox = nullptr; + QMap src_data; + GraphicRanges::Range range_fft; + std::function tf_gr, tf_fft; + QString data_label_x; + QRectF saved_view; + bool saved_autofit = true, show_fft = false; + + PRIVATE_DECLARATION(QAD_GRAPHIC_ANALYSIS_EXPORT) + +public slots: + void clear(); + +private slots: + void gaMousePressEvent(QPointF point, int buttons); + void gaMouseMoveEvent(QPointF point, int buttons); + void gaMouseReleaseEvent(QPointF point, int buttons); + void gaRangeSelected(double start, double end); + void checkSpectrum_toggled(bool on); + void buttonSpectrumRange_toggled(bool on); + void checkSpectrumFixDuration_toggled(bool on); + +signals: + void showSpectrumChanged(bool); + void configChanged(); +}; + + +#endif diff --git a/libs/graphic_analysis/graphic_analysis.ui b/libs/graphic_analysis/graphic_analysis.ui new file mode 100644 index 0000000..6687fd6 --- /dev/null +++ b/libs/graphic_analysis/graphic_analysis.ui @@ -0,0 +1,199 @@ + + + GraphicAnalysis + + + + 0 + 0 + 488 + 57 + + + + + 0 + + + 0 + + + 0 + + + + + Spectrum + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Select spectrum input data + + + + :/icons/axis_x.png:/icons/axis_x.png + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 5 + + + + + + + + false + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Fix dur.: + + + + + + + false + + + s + + + 3 + + + 0.001000000000000 + + + 99999.000000000000000 + + + 10.000000000000000 + + + 100.000000000000000 + + + + + + + + + + + + + Qt::Horizontal + + + + 104 + 0 + + + + + + + + + + + + checkSpectrum + toggled(bool) + widgetSpectrum + setVisible(bool) + + + 90 + 19 + + + 152 + 5 + + + + + checkSpectrumFixDuration + toggled(bool) + spinSpectrumDuration + setEnabled(bool) + + + 209 + 24 + + + 289 + 20 + + + + + buttonSpectrumRange + toggled(bool) + widgetFixedDuration + setEnabled(bool) + + + 126 + 30 + + + 181 + 45 + + + + + diff --git a/libs/graphic_analysis/lang/qad_graphic_analysis_en.ts b/libs/graphic_analysis/lang/qad_graphic_analysis_en.ts new file mode 100644 index 0000000..1738ed1 --- /dev/null +++ b/libs/graphic_analysis/lang/qad_graphic_analysis_en.ts @@ -0,0 +1,32 @@ + + + + + GraphicAnalysis + + + Spectrum + + + + + Select spectrum input data + + + + + Fix dur.: + + + + + s + + + + + Hz + + + + diff --git a/libs/graphic_analysis/lang/qad_graphic_analysis_ru.ts b/libs/graphic_analysis/lang/qad_graphic_analysis_ru.ts new file mode 100644 index 0000000..bcb3d51 --- /dev/null +++ b/libs/graphic_analysis/lang/qad_graphic_analysis_ru.ts @@ -0,0 +1,32 @@ + + + + + GraphicAnalysis + + + Spectrum + Спектр + + + + Select spectrum input data + Выбрать данные для построения спектра + + + + Fix dur.: + Фикс. длит.: + + + + s + с + + + + Hz + Гц + + + diff --git a/libs/graphic_analysis/lang/update.bat b/libs/graphic_analysis/lang/update.bat new file mode 100644 index 0000000..bebfc28 --- /dev/null +++ b/libs/graphic_analysis/lang/update.bat @@ -0,0 +1,2 @@ +lupdate ../ -ts qad_graphic_analysis_ru.ts +lupdate ../ -ts qad_graphic_analysis_en.ts diff --git a/libs/graphic_analysis/plugin/CMakeLists.txt b/libs/graphic_analysis/plugin/CMakeLists.txt new file mode 100644 index 0000000..a5a4d99 --- /dev/null +++ b/libs/graphic_analysis/plugin/CMakeLists.txt @@ -0,0 +1 @@ +qad_plugin(graphic_analysis "Gui;Widgets" "") diff --git a/libs/graphic_analysis/plugin/graphic_analysis_plugin.cpp b/libs/graphic_analysis/plugin/graphic_analysis_plugin.cpp new file mode 100644 index 0000000..a1bc9e8 --- /dev/null +++ b/libs/graphic_analysis/plugin/graphic_analysis_plugin.cpp @@ -0,0 +1,71 @@ +#include "graphic_analysis_plugin.h" + +#include "graphic_analysis.h" + +#include +#include +#include + + +GraphicAnalysisPlugin::GraphicAnalysisPlugin(QObject * parent): QObject(parent) { + m_initialized = m_designer = false; +} + + +void GraphicAnalysisPlugin::initialize(QDesignerFormEditorInterface * core) { + m_designer = true; + if (m_initialized) return; + m_initialized = true; +} + + +bool GraphicAnalysisPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * GraphicAnalysisPlugin::createWidget(QWidget * parent) { + auto ret = new GraphicAnalysis(parent); + if (m_designer) ret->m_fakeGL = true; + return ret; +} + + +QString GraphicAnalysisPlugin::name() const { + return QLatin1String("GraphicAnalysis"); +} + + +QString GraphicAnalysisPlugin::group() const { + return QLatin1String("Display Widgets"); +} + + +QIcon GraphicAnalysisPlugin::icon() const { + return QIcon(":/icons/graphic.png"); +} + + +QString GraphicAnalysisPlugin::toolTip() const { + return QLatin1String(""); // QLatin1String("Widget for display any math graphics with grid and navigation"); +} + + +QString GraphicAnalysisPlugin::whatsThis() const { + return QLatin1String(""); +} + + +bool GraphicAnalysisPlugin::isContainer() const { + return false; +} + + +QString GraphicAnalysisPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString GraphicAnalysisPlugin::includeFile() const { + return QLatin1String("graphic_analysis.h"); +} diff --git a/libs/graphic_analysis/plugin/graphic_analysis_plugin.h b/libs/graphic_analysis/plugin/graphic_analysis_plugin.h new file mode 100644 index 0000000..176cd59 --- /dev/null +++ b/libs/graphic_analysis/plugin/graphic_analysis_plugin.h @@ -0,0 +1,40 @@ +#ifndef GRAPHIC_analysis_PLUGIN_H +#define GRAPHIC_analysis_PLUGIN_H + +#include +#if QT_VERSION >= 0x050000 +# include +#else +# include +#endif + +class GraphicAnalysis; + + +class GraphicAnalysisPlugin + : public QObject + , public QDesignerCustomWidgetInterface { + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + GraphicAnalysisPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized, m_designer; +}; + + +#endif diff --git a/libs/graphic_analysis/plugin/qad_graphic_analysis.cpp b/libs/graphic_analysis/plugin/qad_graphic_analysis.cpp new file mode 100644 index 0000000..709138b --- /dev/null +++ b/libs/graphic_analysis/plugin/qad_graphic_analysis.cpp @@ -0,0 +1,17 @@ +#include "qad_graphic_analysis.h" + +#include "graphic_analysis_plugin.h" + +QADGraphicAnalysis::QADGraphicAnalysis(QObject * parent): QObject(parent) { + m_widgets << new GraphicAnalysisPlugin(this); +} + + +QList QADGraphicAnalysis::customWidgets() const { + return m_widgets; +} + + +#if QT_VERSION < 0x050000 +Q_EXPORT_PLUGIN2(qad_graphic_analysis_plugin, QADGraphicAnalysis) +#endif diff --git a/libs/graphic_analysis/plugin/qad_graphic_analysis.h b/libs/graphic_analysis/plugin/qad_graphic_analysis.h new file mode 100644 index 0000000..d0b2e4f --- /dev/null +++ b/libs/graphic_analysis/plugin/qad_graphic_analysis.h @@ -0,0 +1,24 @@ +#ifndef QAD_GRAPHIC_H +#define QAD_GRAPHIC_H + +#include +#include + +class QADGraphicAnalysis + : public QObject + , public QDesignerCustomWidgetCollectionInterface { + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) +#if QT_VERSION >= 0x050000 + Q_PLUGIN_METADATA(IID "qad.graphic_analysis") +#endif + +public: + explicit QADGraphicAnalysis(QObject * parent = 0); + virtual QList customWidgets() const; + +private: + QList m_widgets; +}; + +#endif // QAD_GRAPHIC_H diff --git a/libs/graphic_analysis/qad_graphic_analysis.qrc b/libs/graphic_analysis/qad_graphic_analysis.qrc new file mode 100644 index 0000000..93e0881 --- /dev/null +++ b/libs/graphic_analysis/qad_graphic_analysis.qrc @@ -0,0 +1,6 @@ + + + ../../icons/axis_x.png + ../../icons/graphic.png + + diff --git a/libs/sql/sql_query.cpp b/libs/sql/sql_query.cpp index f8164fc..a01d760 100644 --- a/libs/sql/sql_query.cpp +++ b/libs/sql/sql_query.cpp @@ -29,6 +29,7 @@ QAD::SQLQuery::Result QAD::SQLQuery::exec(QString query_, QVariantMap params, QS ret.ok = true; ret.rows = q.q.numRowsAffected(); ret.insertId = q.q.lastInsertId(); + ret.query = q.q; return ret; } if (Singleton::instance()->fail_handler) Singleton::instance()->fail_handler(q.q.lastQuery(), params, q.q.lastError()); diff --git a/libs/sql/sql_query.h b/libs/sql/sql_query.h index 8b84cff..0a5d150 100644 --- a/libs/sql/sql_query.h +++ b/libs/sql/sql_query.h @@ -39,6 +39,7 @@ public: bool ok = false; int rows = 0; QVariant insertId = -1; + QSqlQuery query; operator bool() const { return ok; } };