/
MaximU
/
arraywidget
Обзор
Документация
Войти
/
MaximU
/
arraywidget
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
arraywidget.cpp
3 033 строки
107 KB
user
Рефак уствановки мин и макс осей графиков.
29 июл 2026, 13:33
29 июл 2026, 13:33
fc2227c
Код
Авторство
О чём код?
#include "arraywidget.h" #include <QByteArray> #include <QIODevice> #include <QMouseEvent> #include <algorithm> #include <float.h> #include <qwt_plot_canvas.h> #include <qwt_plot_curve.h> #include <qwt_plot_histogram.h> #include <qwt_plot_spectrogram.h> #include <qwt_scale_widget.h> #include "arrayrasterdata.h" #include "colormap.h" #include "conversions.h" #include "customdrawqwtplotitem.h" #include "ui_arraywidget.h" const QColor MapableScaleColor = Qt::darkGreen; //!< Цвет оси с расчетными значениями. const double CurveMargin = 0.5; //!< Отступ отображения набора значений от края графика. /*! * \brief Конструктор. * \param parent Указатель на родительское окно. */ ArrayWidget::ArrayWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ArrayWidgetClass) { ui->setupUi(this); ui->comboboxProviders->setVisible(false); mFont = QApplication::font(); mFont.setPointSize(10); mFont.setBold(true); //// Создание меню кнопки "Авто". mMenuAuto.addAction(ui->actionAutoIndividual); mMenuAuto.addAction(ui->actionAutoCommon); ui->buttonAuto->setMenu(&mMenuAuto); //// Создание меню кнопки "Вращения". QMenu *menu = new QMenu; menu->addAction(ui->actionRotate2); menu->addAction(ui->actionRotateReset); ui->buttonRotate->setMenu(menu); //// mMenus[0] = new QMenu; mMenus[1] = new QMenu; mMenus[2] = new QMenu; mMenus[3] = new QMenu; mActionGroups[0] = new QActionGroup(this); connect(mActionGroups[0], &QActionGroup::triggered, this, &ArrayWidget::slot_menuDimension1_triggered); mActionGroups[1] = new QActionGroup(this); connect(mActionGroups[1], &QActionGroup::triggered, this, &ArrayWidget::slot_menuDimension2_triggered); mActionGroups[2] = new QActionGroup(this); connect(mActionGroups[2], &QActionGroup::triggered, this, &ArrayWidget::slot_menuDimension3_triggered); mActionGroups[3] = new QActionGroup(this); connect(mActionGroups[3], &QActionGroup::triggered, this, &ArrayWidget::slot_menuDimension4_triggered); mDimensionUnitsVariants[0] = -1; mDimensionUnitsVariants[1] = -1; mDimensionUnitsVariants[2] = -1; mDimensionUnitsVariants[3] = -1; mDimensionsCounts[0] = -1; mDimensionsCounts[1] = -1; mDimensionsCounts[2] = -1; mDimensionsCounts[3] = -1; mDimensionsBases[0] = 0; mDimensionsBases[1] = 0; mDimensionsBases[2] = 0; mDimensionsBases[3] = 0; mCurrentIndexes[0] = 0; mCurrentIndexes[1] = 0; mCurrentIndexes[2] = -1; mCurrentIndexes[3] = -1; mDimensionsMap.resize(DimensionCount); mDimensionsMap[0] = 0; mDimensionsMap[1] = 1; mDimensionsMap[2] = 2; mDimensionsMap[3] = 3; connect(ui->buttonShowLeftPlot, &QAbstractButton::toggled, ui->plotsetContainer, &PlotSetContainerWidget::setPlotsetLeftPlotVisible); connect(ui->buttonShowTopPlot, &QAbstractButton::toggled, ui->plotsetContainer, &PlotSetContainerWidget::setPlotsetBottomPlotVisible); connect(ui->buttonWiden, &QAbstractButton::clicked, ui->plotsetContainer, &PlotSetContainerWidget::widenPlotsets); connect(ui->buttonNarrow, &QAbstractButton::clicked, ui->plotsetContainer, &PlotSetContainerWidget::narrowPlotsets); ui->splitter->setSizes({150, 850}); ui->spinboxIndex1->setMinimum(0); ui->spinboxIndex1->setMaximum(0); ui->spinboxDimension2Count->setMinimum(0); ui->spinboxDimension2Count->setMaximum(0); ColorMap *colorMap = new ColorMap; colorMap->setDefaultColor(palette().color(QPalette::Button)); colorMap->setGradientColors({Qt::darkBlue, Qt::blue, Qt::green, Qt::white, Qt::yellow, Qt::darkRed, Qt::red}); ui->widgetLegend->setColorMap(colorMap); ui->widgetLegend->setVisible(false); ui->labelIndex1->installEventFilter(this); ui->labelIndex2->installEventFilter(this); ui->labelIndex3->installEventFilter(this); ui->labelIndex4->installEventFilter(this); setupDimension2Plot(); updateUi(); setInfoPanelVisible(true); } /*! * \brief Деструктор. */ ArrayWidget::~ArrayWidget() { delete ui; delete mMenus[0]; delete mMenus[1]; delete mMenus[2]; delete mMenus[3]; delete mActionGroups[0]; delete mActionGroups[1]; delete mActionGroups[2]; delete mActionGroups[3]; } /*! * \brief Сохраняет настройки приложения в ini-файле. * \param settings Объект сохранения настроек. */ void ArrayWidget::writeSettings(QSettings &settings) { settings.beginGroup(objectName()); settings.setValue("splitterState", splitterState()); settings.setValue("dimension2PlotVisible", isDimension2PlotVisible()); settings.beginWriteArray("schemes"); for (int i = 0; i < DimensionCount; i ++) { settings.setArrayIndex(i); settings.setValue("scheme", schemeToString(mSchemes[i])); } settings.endArray(); settings.setValue("plotsetHeight", plotsetHeight()); settings.setValue("plotsetDivision", plotsetDivision()); settings.setValue("plotsetLeftPlotVisible", isPlotsetLeftPlotVisible()); settings.setValue("plotsetBottomPlotVisible", isPlotsetBottomPlotVisible()); settings.setValue("plotsetAuto", isAuto()); settings.setValue("plotsetAutoCommon", isAutoCommon()); settings.setValue("plotsetDB", isDB()); if (mAllowRotation) { settings.beginWriteArray("dimensionMap"); std::vector<int> map = dimensionsMap(); for (int i = 0; i < DimensionCount; i ++) { settings.setArrayIndex(i); settings.setValue("map", map[i]); } settings.endArray(); } settings.setValue("providersScheme", providersScheme()); settings.setValue("currentProviderListIndex", currentProviderListIndex()); settings.setValue("infoVisible", isInfoVisible()); settings.setValue("dimensionUnitVariants[0]", mDimensionUnitsVariants[0]); settings.setValue("dimensionUnitVariants[1]", mDimensionUnitsVariants[1]); settings.setValue("dimensionUnitVariants[2]", mDimensionUnitsVariants[2]); settings.setValue("dimensionUnitVariants[3]", mDimensionUnitsVariants[3]); settings.endGroup(); } /*! * \brief Восстанавливает настройки приложения из ini-файла. * \param settings Объект сохранения настроек. */ void ArrayWidget::readSettings(QSettings &settings) { mLockUpdate = true; settings.beginGroup(objectName()); setSplitterState(settings.value("splitterState", splitterState()).toByteArray()); setDimension2PlotVisible(settings.value("dimension2PlotVisible", isDimension2PlotVisible()).toBool()); settings.beginWriteArray("schemes"); for (int i = 0; i < DimensionCount; i ++) { settings.setArrayIndex(i); mSchemes[i] = stringToScheme(settings.value(("scheme"), schemeToString(mSchemes[i])).toString()); } settings.endArray(); setPlotsetHeight(settings.value("plotsetHeight", plotsetHeight()).toInt()); setPlotsetDivision(settings.value("plotsetDivision", plotsetDivision()).toSizeF()); setPlotsetLeftPlotVisible(settings.value("plotsetLeftPlotVisible", isPlotsetLeftPlotVisible()).toBool()); setPlotsetBottomPlotVisible(settings.value("plotsetBottomPlotVisible", isPlotsetBottomPlotVisible()).toBool()); setAuto(settings.value("plotsetAuto", isAuto()).toBool()); setAutoCommon(settings.value("plotsetAutoCommon", isAutoCommon()).toBool()); setDB(settings.value("plotsetDB", isDB()).toBool()); if (mAllowRotation) { settings.beginReadArray("dimensionMap"); std::vector<int> map = dimensionsMap(); for (int i = 0; i < DimensionCount; i ++) { settings.setArrayIndex(i); map[i] = settings.value("map", map[i]).toInt(); } setDimensionsMap(map); settings.endArray(); } setProvidersScheme(settings.value("providersScheme", providersScheme()).toByteArray()); setCurrentProviderListIndex(settings.value("currentProviderListIndex", currentProviderListIndex()).toInt()); setInfoPanelVisible(settings.value("infoVisible", true).toBool()); mDimensionUnitsVariants[0] = settings.value("dimensionUnitVariants[0]", mDimensionUnitsVariants[0]).toInt(); if (!mDimensionsUnits[0].isEmpty() && mDimensionUnitsVariants[0] == -1) { mDimensionUnitsVariants[0] = 0; } if (mDimensionsUnits[0].isEmpty() && mDimensionUnitsVariants[0] != -1) { mDimensionUnitsVariants[0] = -1; } mDimensionUnitsVariants[1] = settings.value("dimensionUnitVariants[1]", mDimensionUnitsVariants[1]).toInt(); if (!mDimensionsUnits[1].isEmpty() && mDimensionUnitsVariants[1] == -1) { mDimensionUnitsVariants[1] = 0; } if (mDimensionsUnits[1].isEmpty() && mDimensionUnitsVariants[1] != -1) { mDimensionUnitsVariants[1] = -1; } mDimensionUnitsVariants[2] = settings.value("dimensionUnitVariants[2]", mDimensionUnitsVariants[2]).toInt(); if (!mDimensionsUnits[2].isEmpty() && mDimensionUnitsVariants[2] == -1) { mDimensionUnitsVariants[2] = 0; } if (mDimensionsUnits[2].isEmpty() && mDimensionUnitsVariants[2] != -1) { mDimensionUnitsVariants[2] = -1; } mDimensionUnitsVariants[3] = settings.value("dimensionUnitVariants[3]", mDimensionUnitsVariants[3]).toInt(); if (!mDimensionsUnits[3].isEmpty() && mDimensionUnitsVariants[3] == -1) { mDimensionUnitsVariants[3] = 0; } if (mDimensionsUnits[3].isEmpty() && mDimensionUnitsVariants[3] != -1) { mDimensionUnitsVariants[3] = -1; } settings.endGroup(); setScheme(mDimensionsMap[1], mSchemes[mDimensionsMap[1]]); mLockUpdate = false; updateView(); } /*! * \brief Фильтр событий. * \param obj Объект, для которого обрабатывается событие. * \param event Событие. * \return true, если событие обработано. */ bool ArrayWidget::eventFilter(QObject *obj, QEvent *event) { if (auto *mouseEvent = dynamic_cast<QMouseEvent *>(event)) { if (obj == ui->plotDimension2->canvas()) { QPointF pt = mouseEvent->pos(); pt.setX(ui->plotDimension2->invTransform(QwtPlot::xBottom, pt.x())); pt.setY(ui->plotDimension2->invTransform(QwtPlot::yRight, pt.y())); switch (mouseEvent->type()) { case QEvent::MouseButtonPress: on_plotsetContainer_mousePress(0, PlotIDLeftLeftPlot, pt, mouseEvent->buttons()); break; case QEvent::MouseMove: on_plotsetContainer_mouseMove(0, PlotIDLeftLeftPlot, pt, mouseEvent->buttons()); break; case QEvent::MouseButtonRelease: on_plotsetContainer_mouseRelease(0, PlotIDLeftLeftPlot, pt, mouseEvent->buttons()); break; default: break; } } else { if (mouseEvent->type() == QEvent::MouseButtonRelease) { if (obj == ui->labelIndex1) { if (mActionGroups[0]->actions().count() > 1) { if (mDimensionUnitsVariants[0] != -1) { mActionGroups[0]->actions().at(mDimensionUnitsVariants[0])->setChecked(true); } mMenus[0]->popup(mouseEvent->globalPos()); } } if (obj == ui->labelIndex2) { if (mActionGroups[1]->actions().count() > 1) { if (mDimensionUnitsVariants[1] != -1) { mActionGroups[1]->actions().at(mDimensionUnitsVariants[1])->setChecked(true); } mMenus[1]->popup(mouseEvent->globalPos()); } } if (obj == ui->labelIndex3) { if (mActionGroups[2]->actions().count() > 1) { if (mDimensionUnitsVariants[2] != -1) { mActionGroups[2]->actions().at(mDimensionUnitsVariants[2])->setChecked(true); } mMenus[2]->popup(mouseEvent->globalPos()); } } if (obj == ui->labelIndex4) { if (mActionGroups[3]->actions().count() > 1) { if (mDimensionUnitsVariants[3] != -1) { mActionGroups[3]->actions().at(mDimensionUnitsVariants[3])->setChecked(true); } mMenus[3]->popup(mouseEvent->globalPos()); } } } } } return QWidget::eventFilter(obj, event); } /*! * \brief Инициализирует график Dimension2. */ void ArrayWidget::setupDimension2Plot() { //// Установка видимости осей. ui->plotDimension2->enableAxis(QwtPlot::yLeft, true); ui->plotDimension2->enableAxis(QwtPlot::xTop, true); ui->plotDimension2->enableAxis(QwtPlot::yRight, true); ui->plotDimension2->enableAxis(QwtPlot::xBottom, true); //// Установка вертикального текста для осей. ui->plotDimension2->setAxisLabelRotation(QwtPlot::yLeft, -90); ui->plotDimension2->setAxisLabelRotation(QwtPlot::yRight, -90); //// Установка шрифта для осей. QFont font = QApplication::font(); font.setPointSize(7); ui->plotDimension2->setAxisFont(QwtPlot::yLeft, font); ui->plotDimension2->setAxisFont(QwtPlot::xTop, font); ui->plotDimension2->setAxisFont(QwtPlot::yRight, font); ui->plotDimension2->setAxisFont(QwtPlot::xBottom, font); //// Установка цвета оси. QPalette palette; palette = ui->plotDimension2->axisWidget(QwtPlot::yRight)->palette(); palette.setColor(QPalette::Text, MapableScaleColor); palette.setColor(QPalette::WindowText, MapableScaleColor); ui->plotDimension2->axisWidget(QwtPlot::yRight)->setPalette(palette); //// Установка шкал графика по умолчанию. ui->plotDimension2->setAxisScale(QwtPlot::yLeft, -CurveMargin, CurveMargin, 1); ui->plotDimension2->setAxisScale(QwtPlot::xTop, 0, 1, 1); ui->plotDimension2->setAxisScale(QwtPlot::yRight, -CurveMargin, CurveMargin, 1); ui->plotDimension2->setAxisScale(QwtPlot::xBottom, 0, 1, 1); //// Пикер отображения координат на графике. ui->plotDimension2->initDisplayCoordinatePicker(QwtPlot::xBottom, QwtPlot::yLeft, QwtPlotExt::PickerDragPointMachine); //// Инициализация координатной сетки графиков. ui->plotDimension2->initGrid(); //// Добавление отрисовки заднего плана графика. CustomDrawQwtPlotItem *backgroundItem = new CustomDrawQwtPlotItem(); backgroundItem->setYAxis(QwtPlot::yRight); backgroundItem->setXAxis(QwtPlot::xBottom); connect(backgroundItem, &CustomDrawQwtPlotItem::drawContent, this, &ArrayWidget::slot_leftLeftPlot_drawBackground); backgroundItem->attach(ui->plotDimension2); //// Добавление отрисовки переднего плана графика. CustomDrawQwtPlotItem *foregroundItem = new CustomDrawQwtPlotItem(); foregroundItem->setYAxis(QwtPlot::yRight); foregroundItem->setXAxis(QwtPlot::xBottom); connect(foregroundItem, &CustomDrawQwtPlotItem::drawContent, this, &ArrayWidget::slot_leftLeftPlot_drawForeground); foregroundItem->attach(ui->plotDimension2); //// Установка фильтра событий для обработки действий мыши. ui->plotDimension2->canvas()->installEventFilter(this); } /*! * \brief Устанавливает название измерения 1. * \param name Название измерения 1. */ void ArrayWidget::setDimension1Name(const QString &name) { mDimensionsNames[0] = name; ui->labelDimension1->setText(mDimensionsNames[0]); } /*! * \brief Устанавливает название измерения 2. * \param name Название измерения 2. */ void ArrayWidget::setDimension2Name(const QString &name) { mDimensionsNames[1] = name; ui->labelDimension2->setText(mDimensionsNames[1]); ui->plotsetContainer->setPlotsetTitleFormat(mDimensionsNames[1] + " №%1"); } /*! * \brief Устанавливает название измерения 3. * \param name Название измерения 3. */ void ArrayWidget::setDimension3Name(const QString &name) { mDimensionsNames[2] = name; } /*! * \brief Устанавливает название измерения 4. * \param name Название измерения 4. */ void ArrayWidget::setDimension4Name(const QString &name) { mDimensionsNames[3] = name; } /*! * \brief Добавляет название единицы измерения 1, а также вариант отображения номера отсчета в шкалу. * \param unit Название единицы измерения 1. */ void ArrayWidget::addDimension1Unit(const QString &unit) { if (mDimensionsUnits[0].isEmpty()) { QSize size = ui->labelIndex1->minimumSize(); size.rwidth() *= 1.5; ui->labelIndex1->setMinimumSize(size); } //// Формирование списка единиц измерения. mDimensionsUnits[0].append(unit); if (mDimensionUnitsVariants[0] == -1) { mDimensionUnitsVariants[0] = 0; } //// Формирование меню единиц измерения. mMenus[0]->setEnabled(true); QAction *action = mMenus[0]->addAction(unit); action->setData(mDimensionsUnits[0].count() - 1); action->setCheckable(true); mActionGroups[0]->addAction(action); } /*! * \brief Добавляет название единицы измерения 2, а также вариант отображения номера отсчета в шкалу. * \param unit Название единицы измерения 2. */ void ArrayWidget::addDimension2Unit(const QString &unit) { if (mDimensionsUnits[1].isEmpty()) { QSize size = ui->labelIndex2->minimumSize(); size.rwidth() *= 1.5; ui->labelIndex2->setMinimumSize(size); } //// Формирование списка единиц измерения. mDimensionsUnits[1].append(unit); if (mDimensionUnitsVariants[1] == -1) { mDimensionUnitsVariants[1] = 0; } //// Формирование меню единиц измерения. mMenus[1]->setEnabled(true); QAction *action = mMenus[1]->addAction(unit); action->setData(mDimensionsUnits[1].count() - 1); action->setCheckable(true); mActionGroups[1]->addAction(action); } /*! * \brief Добавляет название единицы измерения 3, а также вариант отображения номера отсчета в шкалу. * \param unit Название единицы измерения 3. */ void ArrayWidget::addDimension3Unit(const QString &unit) { if (mDimensionsUnits[2].isEmpty()) { QSize size = ui->labelIndex3->minimumSize(); size.rwidth() *= 1.5; ui->labelIndex3->setMinimumSize(size); } //// Формирование списка единиц измерения. mDimensionsUnits[2].append(unit); if (mDimensionUnitsVariants[2] == -1) { mDimensionUnitsVariants[2] = 0; } //// Формирование меню единиц измерения. mMenus[2]->setEnabled(true); QAction *action = mMenus[2]->addAction(unit); action->setData(mDimensionsUnits[2].count() - 1); action->setCheckable(true); mActionGroups[2]->addAction(action); } /*! * \brief Добавляет название единицы измерения 4, а также вариант отображения номера отсчета в шкалу. * \param unit Название единицы измерения 4. */ void ArrayWidget::addDimension4Unit(const QString &unit) { if (mDimensionsUnits[3].isEmpty()) { QSize size = ui->labelIndex4->minimumSize(); size.rwidth() *= 1.5; ui->labelIndex4->setMinimumSize(size); } //// Формирование списка единиц измерения. mDimensionsUnits[3].append(unit); if (mDimensionUnitsVariants[3] == -1) { mDimensionUnitsVariants[3] = 0; } //// Формирование меню единиц измерения. mMenus[3]->setEnabled(true); QAction *action = mMenus[3]->addAction(unit); action->setData(mDimensionsUnits[3].count() - 1); action->setCheckable(true); mActionGroups[3]->addAction(action); } /*! * \brief Устанавливает количество значений в измерении 1. * \param count Количество значений. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension1Count(int count, bool update) { if (mDimensionsCounts[0] != count) { mDimensionsCounts[0] = count; ui->spinboxIndex1->setMinimum(mDimensionsBases[0]); ui->spinboxIndex1->setMaximum(mDimensionsBases[0] + mDimensionsCounts[0] - 1); if (mDimensionsCounts[0] > 1) { ui->spinboxIndex1->setVisible(true); ui->labelDimension1->setVisible(true); ui->lineButtons->setVisible(true); ui->labelIndex1->setVisible(true); } else { ui->spinboxIndex1->setVisible(false); ui->labelDimension1->setVisible(false); ui->lineButtons->setVisible(false); ui->labelIndex1->setVisible(false); } foreach (auto providerList, mDataProvidersListsList) { foreach (auto *provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionCount(0, mDimensionsCounts[0]); } } } if (mCurrentIndexes[mDimensionsMap[0]] >= mDimensionsCounts[0]) { mCurrentIndexes[mDimensionsMap[0]] = -1; } if (update) { updateView(); } } } /*! * \brief Устанавливает количество значений в измерении 2. * \param count Количество значений. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension2Count(int count, bool update) { if (mDimensionsCounts[1] != count) { mDimensionsCounts[1] = count; ui->spinboxDimension2Count->setMinimum(mDimensionsBases[1]); ui->spinboxDimension2Count->setMaximum(mDimensionsBases[1] + mDimensionsCounts[1]); if (mDimensionsCounts[1] > 1) { ui->buttonShowDimension2Plot->setVisible(true); ui->labelDimension2->setVisible(true); ui->spinboxDimension2Count->setVisible(true); ui->spinboxIndexes2->setVisible(true); ui->line1->setVisible(true); ui->line2->setVisible(true); ui->line3->setVisible(true); ui->buttonWiden->setVisible(true); ui->buttonNarrow->setVisible(true); ui->plotDimension2->setVisible(isDimension2PlotVisible()); // Отображение заголовка набора графиков. foreach (auto widget, ui->plotsetContainer->plotsets()) { widget->setTitleVisible(true); } } else { ui->buttonShowDimension2Plot->setVisible(false); ui->labelDimension2->setVisible(false); ui->spinboxDimension2Count->setVisible(false); ui->spinboxIndexes2->setVisible(false); ui->line1->setVisible(false); ui->line2->setVisible(false); ui->line3->setVisible(false); ui->buttonWiden->setVisible(false); ui->buttonNarrow->setVisible(false); ui->plotDimension2->setVisible(false); ui->labelIndex2->setVisible(false); // Установка одного постоянного набора графиков. ui->plotsetContainer->setScheme({0}); // Отображение заголовка набора графиков. foreach (auto widget, ui->plotsetContainer->plotsets()) { widget->setTitleVisible(false); } } foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionCount(1, mDimensionsCounts[1]); } } } if (mCurrentIndexes[mDimensionsMap[1]] >= mDimensionsCounts[1]) { mCurrentIndexes[mDimensionsMap[1]] = -1; } if (update) { updateView(); } } } /*! * \brief Устанавливает количество значений в измерении 3. * \param count Количество значений. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension3Count(int count, bool update) { if (mDimensionsCounts[2] != count) { mDimensionsCounts[2] = count; foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionCount(2, mDimensionsCounts[2]); } } } if (mCurrentIndexes[mDimensionsMap[2]] >= mDimensionsCounts[2]) { mCurrentIndexes[mDimensionsMap[2]] = -1; } if (update) { updateView(); } } } /*! * \brief Устанавливает количество значений в измерении 4. * \param count Количество значений. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension4Count(int count, bool update) { if (mDimensionsCounts[3] != count) { mDimensionsCounts[3] = count; foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionCount(3, mDimensionsCounts[3]); } } } if (mCurrentIndexes[mDimensionsMap[3]] >= mDimensionsCounts[3]) { mCurrentIndexes[mDimensionsMap[3]] = -1; } if (update) { updateView(); } } } /*! * \brief Устанавливает отображаемый начальный индекс. * \param base Отображаемый начальный индекс. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension1Base(int base, bool update) { if (mDimensionsBases[0] != base) { mDimensionsBases[0] = base; ui->spinboxIndex1->setMinimum(mDimensionsBases[0]); ui->spinboxIndex1->setMaximum(mDimensionsBases[0] + mDimensionsCounts[0] - 1); foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionBase(0, mDimensionsBases[0]); } } } if (update) { updateView(); } } } /*! * \brief Устанавливает отображаемый начальный индекс. * \param base Отображаемый начальный индекс. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension2Base(int base, bool update) { if (mDimensionsBases[1] != base) { mDimensionsBases[1] = base; foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionBase(1, mDimensionsBases[1]); } } } if (update) { updateView(); } } } /*! * \brief Устанавливает отображаемый начальный индекс. * \param base Отображаемый начальный индекс. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension3Base(int base, bool update) { if (mDimensionsBases[2] != base) { mDimensionsBases[2] = base; foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionBase(2, mDimensionsBases[2]); } } } if (update) { updateView(); } } } /*! * \brief Устанавливает отображаемый начальный индекс. * \param base Отображаемый начальный индекс. * \param update Признак выполнения обновления после установки значения. */ void ArrayWidget::setDimension4Base(int base, bool update) { if (mDimensionsBases[3] != base) { mDimensionsBases[3] = base; foreach (auto providerList, mDataProvidersListsList) { foreach (auto provider, providerList) { if (auto *adp = dynamic_cast<ArrayDataProvider *>(provider)) { adp->setDimensionBase(3, mDimensionsBases[3]); } } } if (update) { updateView(); } } } /*! * \brief Устанавливает видимость графика каналов. * \param visible Признак видимости графика Измерения 2. */ void ArrayWidget::setDimension2PlotVisible(bool visible) { ui->buttonShowDimension2Plot->setChecked(visible); } /*! * \brief Возвращает признак видимости графика каналов. * \param visible Признак видимости графика Измерения 2. */ bool ArrayWidget::isDimension2PlotVisible() { return ui->buttonShowDimension2Plot->isChecked(); } /*! * \brief Устанавливает схему контейнера. * \param dimension Индекс измерения. * \param scheme Список устанавливаемых значений свойств наборов графиков, помещенных в контейнер. Кол-во наборов определяется размером списка. */ void ArrayWidget::setScheme(int dimension, const QVariantList &scheme) { mSchemes[dimension] = scheme; //// Проверка схемы на выход за границы массивов. for (int i = mSchemes[dimension].count() - 1; i >= 0; i --) { bool ok; int index = mSchemes[dimension][i].toInt(&ok); if (!ok || index < mDimensionsBases[dimension] || mDimensionsBases[dimension] + mDimensionsCounts[dimension] - 1 < index) { mSchemes[dimension].removeAt(i); } } //// if (scheme.isEmpty()) { mCurrentIndexes[mDimensionsMap[2]] = -1; mCurrentIndexes[mDimensionsMap[3]] = -1; updateView(); } ui->plotsetContainer->setScheme(mSchemes[dimension]); } /*! * \brief Возвращает текущую схему (список специальных значений каждого набора) контейнера. * \param dimension Индекс измерения. * \return Текцщая схема. */ QVariantList ArrayWidget::scheme(int dimension) const { return mSchemes[dimension]; } /*! * \brief Устанавливает высоту наборов графиков. * \param height Высота наборов графиков. */ void ArrayWidget::setPlotsetHeight(int height) { ui->plotsetContainer->setPlotsetHeight(height); } /*! * \brief Возвращает высоту наборов графиков. * \return Высота наборов графиков. */ int ArrayWidget::plotsetHeight() { return ui->plotsetContainer->plotsetHeight(); } /*! * \brief Устанавливает пропорции ширины и высоты графиков. * \param division Пропорции ширины и высоты графиков. */ void ArrayWidget::setPlotsetDivision(QSizeF division) { ui->plotsetContainer->setPlotsetDivision(division); } /*! * \brief Возвращает пропорции ширины и высоты графиков. * \return Пропорции ширины и высоты графиков. */ QSizeF ArrayWidget::plotsetDivision() { return ui->plotsetContainer->plotsetDivision(); } /*! * \brief Устанавливает признак отображения левого графика набора. * \param visible Признак отображения левого графика набора. */ void ArrayWidget::setPlotsetLeftPlotVisible(bool visible) { ui->buttonShowLeftPlot->setChecked(visible); } /*! * \brief Возвращает признак отображения левого графика набора. * \return Признак отображения левого графика набора. */ bool ArrayWidget::isPlotsetLeftPlotVisible() { return ui->plotsetContainer->isPlotsetLeftPlotVisible(); } /*! * \brief Устанавливает признак отображения нижнего графика набора. * \param visible Признак отображения нижнего графика набора. */ void ArrayWidget::setPlotsetBottomPlotVisible(bool visible) { ui->buttonShowTopPlot->setChecked(visible); } /*! * \brief Возвращает признак отображения нижнего графика набора. * \return Признак отображения нижнего графика набора. */ bool ArrayWidget::isPlotsetBottomPlotVisible() { return ui->plotsetContainer->isPlotsetBottomPlotVisible(); } /*! * \brief Возвращает признак автомасштабирования. * \return Признак автомасштабирования. */ bool ArrayWidget::isAuto() { return mAuto; } /*! * \brief Устанавливает признак автомасштабирования. * \param auto Признак автомасштабирования. */ void ArrayWidget::setAuto(bool value) { mAuto = value; updateUi(); updateView(); } /*! * \brief Возвращает признак автомасштабирования. * \return Признак автомасштабирования. */ bool ArrayWidget::isAutoCommon() { return mAutoCommon; } /*! * \brief Устанавливает признак автомасштабирования. * \param auto Признак автомасштабирования. */ void ArrayWidget::setAutoCommon(bool value) { mAutoCommon = value; updateUi(); updateView(); } /*! * \brief Возаращает признак отображения в дБ. * \return Признак отображения в дБ. */ bool ArrayWidget::isDB() { return mDB; } /*! * \brief Устанавливает признак отображения в дБ. * \param dB Признак отображения в дБ. */ void ArrayWidget::setDB(bool value) { mDB = value; ui->widgetLegend->updateUi(); ui->plotDimension2->resetZoomStack(); ui->plotsetContainer->resetZoomStack(); updateUi(); updateView(); } /*! * \brief Возвращает массив карты отображения размерностей. * \return Карта отображения размерностей. */ std::vector<int> ArrayWidget::dimensionsMap() { return mDimensionsMap; } /*! * \brief Устанавливает массив карты отображения размерностей. * \param map Карта отображения размерностей. */ void ArrayWidget::setDimensionsMap(std::vector<int> map) { if (mDimensionsMap != map) { if (!(mDimensionsMap[2] == map[3] && mDimensionsMap[3] == map[2])) // При вращении центрального графика выбранные индексы не сбрасываются. { mCurrentIndexes[map[2]] = -1; mCurrentIndexes[map[3]] = -1; } if (mDimensionsMap[1] == map[2] && mDimensionsMap[2] == map[1]) { mCurrentIndexes[map[1]] = -1; mCurrentIndexes[map[2]] = -1; mCurrentIndexes[map[3]] = -1; } mDimensionsMap = map; //// Установка заголовков. ui->labelDimension2->setText(mDimensionsNames[mDimensionsMap[1]]); ui->plotsetContainer->setPlotsetTitleFormat(mDimensionsNames[mDimensionsMap[1]] + " №%1"); //// Установка схемы. mLockUpdate = true; setScheme(mDimensionsMap[1], mSchemes[mDimensionsMap[1]]); mLockUpdate = false; updateView(); } } /*! * \brief Возвращает признак вращения графиковю * \return Признак вращения графиков. */ bool ArrayWidget::isAllowRotation() { return mAllowRotation; } /*! * \brief Разрешает/запрещает вращение графиковю * \param allow Признак вращения графиков. */ void ArrayWidget::setAllowRotation(bool allow) { mAllowRotation = allow; if (mAllowRotation) { ui->buttonRotate->setVisible(true); } else { ui->buttonRotate->setVisible(false); } } /*! * \brief Возвращает индекс отображаемого списка провайдеров. * \return Индекс отображаемого списка провайдеров. */ int ArrayWidget::currentProviderListIndex() { return mCurrentProviderListIndex; } /*! * \brief Устанавливает индекс отображаемого списка провайдеров. * \param index Индекс отображаемого списка провайдеров. */ void ArrayWidget::setCurrentProviderListIndex(int index) { //// Скрытие всех item-ов, соответствующих текущему списку отображаемых провайдеров. QList<DataProvider *> providerList; getProviderList(providerList); if (!providerList.isEmpty()) { auto iterator = providerList.end(); for (-- iterator; iterator != providerList.begin(); -- iterator) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*iterator)) { QwtPlotItem *item; //// График LeftLeft. item = mItemsMap[provider]; item->setVisible(false); //// foreach (auto plotset, ui->plotsetContainer->plotsets()) { //// График Left. item = plotset->plotItem(PlotSetWidget::PlotIDLeftPlot, provider); item->setVisible(false); //// График Bottom. item = plotset->plotItem(PlotSetWidget::PlotIDBottomPlot, provider); item->setVisible(false); } } } } //// mCurrentProviderListIndex = index; ui->widgetLegend->updateView(); ui->widgetLegend->updateUi(); updateView(); } /*! * \brief Возвращает минмальное значение. * \return Минимальное значение. */ double ArrayWidget::minimum() { return mMinimum; } /*! * \brief Устанавливает минмальное значение. * \param value Минимальное значение. */ void ArrayWidget::setMinimum(double value) { mMinimum = value; updateView(); updateUi(); } /*! * \brief Возвращает максимальное значение. * \return Максимальное значение. */ double ArrayWidget::maximum() { return mMaximum; } /*! * \brief Устанавливает максимальное значение. * \param value Максимальное значение. */ void ArrayWidget::setMaximum(double value) { mMaximum = value; updateView(); updateUi(); } /*! * \brief Модифицирует значения в случае равенства для установки шкал графиков. * \param min Минимум. * \param max Максимум. */ void ArrayWidget::checkMinMax(double &min, double &max) { if (min == +FLT_MAX && max == -FLT_MAX) { min = -1; max = 1; } if (min == max) { min -= min * 0.1; max += max * 0.1; } if (min == max) { min -= 1; max += 1; } } /*! * \brief Добавляет список одновременно отображаемых провайдеров данных. * \param label Название списка одновременно отображаемых провайдеров данных. * \param providerList Список одновременно отображаемых провайдеров данных. */ void ArrayWidget::addDataProviderList(const QString &label, const QList<DataProvider *> &providerList) { mDataProvidersListsList.append(providerList); QwtPlotItem *item = ui->plotDimension2->itemList().last(); //// Добавление объектов отображения для каждого провайдера кроме первого, используемого для отображения цветового графика. auto iterator = providerList.end(); for (-- iterator; iterator != providerList.begin(); -- iterator) // В обратном порядке чтобы первый провайдер в списке отображался поверх остальных. { QwtPlotItem *plotItem = nullptr; if (auto *provider = dynamic_cast<ArrayDataProvider *>(*iterator)) { if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *plotCurve = new QwtPlotCurve(); plotCurve->setPen(provider->color()); plotItem = plotCurve; } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *plotHistogram = new QwtPlotHistogram(); plotHistogram->setPen(provider->color()); plotHistogram->setBrush(provider->color()); plotItem = plotHistogram; } else { throw 0; } plotItem->setYAxis(QwtPlot::yRight); plotItem->attach(ui->plotDimension2); } mItemsMap.insert(*iterator, plotItem); } item->setZ(ui->plotDimension2->itemList().last()->z() + 1); //// mLockUpdate = true; ui->comboboxProviders->addItem(label); ui->comboboxProviders->setVisible(mDataProvidersListsList.count() > 1); mLockUpdate = false; updateView(); } /*! * \brief Обновляет содержимое окна. */ void ArrayWidget::updateView() { if (!mLockUpdate) { QList<DataProvider *> providerList; getProviderList(providerList); int dimension1Base = mDimensionsBases[mDimensionsMap[1]]; int dimension2Base = mDimensionsBases[mDimensionsMap[2]]; int dimension3Base = mDimensionsBases[mDimensionsMap[3]]; int dimension1Count = mDimensionsCounts[mDimensionsMap[1]]; //// Формирование индексов в соответствии с отображаемыми размерностями. int index0 = mCurrentIndexes[mDimensionsMap[0]]; int index2 = mCurrentIndexes[mDimensionsMap[2]]; int index3 = mCurrentIndexes[mDimensionsMap[3]]; //// int vector[DimensionCount]; vector[mDimensionsMap[0]] = index0; vector[mDimensionsMap[1]] = -1; vector[mDimensionsMap[2]] = index2; vector[mDimensionsMap[3]] = index3; //// Заполнение данными. if (!providerList.isEmpty()) { if (index2 != -1 && index3 != -1) { std::vector<double> tmpx(dimension1Count); std::vector<double> tmpy(dimension1Count); //// Заполнение фиксированной оси графика. for (int i = 0; i < dimension1Count; i ++) { tmpy[i] = dimension1Base + i; } //// 0-й провайдер пропускается, т.к. он используется для отображения цветового графика. for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { if (provider->isVisible()) { double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; provider->fetch(tmpx.data(), pfunc, vector[0], vector[1], vector[2], vector[3]); if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(mItemsMap[provider]); curve->setSamples(tmpx.data(), tmpy.data(), dimension1Count); curve->setVisible(true); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(mItemsMap[provider]); histogram->setSamples(nullptr); histogram->setVisible(false); } else { throw 0; } } else { if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(mItemsMap[provider]); curve->setSamples(nullptr, nullptr, 0); curve->setVisible(false); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(mItemsMap[provider]); histogram->setSamples(nullptr); histogram->setVisible(false); } else { throw 0; } } } } } else { for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(mItemsMap[provider]); curve->setSamples(nullptr, nullptr, 0); curve->setVisible(false); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(mItemsMap[provider]); histogram->setSamples(nullptr); histogram->setVisible(false); } else { throw 0; } } } } } //// Расчет минимума и максимума графика. double dimension1PlotMin = +FLT_MAX; double dimension1PlotMax = -FLT_MAX; if (mAuto) { if (!providerList.isEmpty() && index2 != -1 && index3 != -1) { //// Расчет минимума и максимума левого левого графика. /// 0-й провайдер пропускается, т.к. он используется для отображения цветового графика. for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { if (provider->isVisible()) { if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(mItemsMap[provider]); dimension1PlotMin = std::min(dimension1PlotMin, curve->dataRect().left()); dimension1PlotMax = std::max(dimension1PlotMax, curve->dataRect().right()); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; double min = +FLT_MAX; double max = -FLT_MAX; provider->minMax(min, max, vector[0], vector[1], vector[2], vector[3]); dimension1PlotMin = std::min(dimension1PlotMin, pfunc(min)); dimension1PlotMax = std::max(dimension1PlotMax, pfunc(max)); } else { throw 0; } } } } } else { double (* pfunc)(double) = mDB ? todB_s : noop; dimension1PlotMin = pfunc(mMinimum); dimension1PlotMax = pfunc(mMaximum); } } else { double (* pfunc)(double) = mDB ? todB_s : noop; dimension1PlotMin = pfunc(mMinimum); dimension1PlotMax = pfunc(mMaximum); } checkMinMax(dimension1PlotMin, dimension1PlotMax); //// Установка шкал графика. double xyMin[DimensionCount]; double xyMax[DimensionCount]; xyMin[0] = mDimensionsBases[0] - CurveMargin; xyMax[0] = mDimensionsBases[0] + mDimensionsCounts[0] - CurveMargin; xyMin[1] = mDimensionsBases[1] - CurveMargin; xyMax[1] = mDimensionsBases[1] + mDimensionsCounts[1] - CurveMargin; xyMin[2] = mDimensionsBases[2] - CurveMargin; xyMax[2] = mDimensionsBases[2] + mDimensionsCounts[2] - CurveMargin; xyMin[3] = mDimensionsBases[3] - CurveMargin; xyMax[3] = mDimensionsBases[3] + mDimensionsCounts[3] - CurveMargin; double value1Min = xyMin[mDimensionsMap[1]]; double value1Max = xyMax[mDimensionsMap[1]]; emit mapCoordinate(mDimensionsMap[1], mDimensionUnitsVariants[mDimensionsMap[1]], xyMin[0], xyMin[1], xyMin[2], xyMin[3], value1Min); emit mapCoordinate(mDimensionsMap[1], mDimensionUnitsVariants[mDimensionsMap[1]], xyMax[0], xyMax[1], xyMax[2], xyMax[3], value1Max); QRectF rect1(dimension1PlotMin, xyMin[mDimensionsMap[1]], dimension1PlotMax - dimension1PlotMin, xyMax[mDimensionsMap[1]] - xyMin[mDimensionsMap[1]]); QRectF rect2(dimension1PlotMin, value1Min, dimension1PlotMax - dimension1PlotMin, value1Max - value1Min); ui->plotDimension2->setZoomBase(rect1, rect2); //// Подписи к осям. QwtText title; title.setFont(mFont); //// Левый левый график. if (index2 != -1 && index3 != -1) { title.setText(mDimensionsNames[mDimensionsMap[2]] + tr(" №") + QString::number(dimension2Base + index2) + ", " + mDimensionsNames[mDimensionsMap[3]] + tr(" №") + QString::number(dimension3Base + index3)); } else { title.setText(QString()); } ui->plotDimension2->axisWidget(QwtPlot::yLeft)->setTitle(title); //// ui->plotDimension2->replot(); //// Обновление наборов графиков. ui->plotsetContainer->updateView(); QString text; emit updateInformationText(text); ui->labelInformation->setText(text); ui->widget->setVisible(!text.isEmpty()); //// Установка текущего индекса в списке провайдеров. ui->comboboxProviders->setCurrentIndex(mCurrentProviderListIndex); } } /*! * \brief Обновляет состояния элементов пользовательского интерфейса. */ void ArrayWidget::updateUi() { ui->spinboxIndex1->blockSignals(true); ui->spinboxIndex1->setValue(mCurrentIndexes[mDimensionsMap[0]] + mDimensionsBases[mDimensionsMap[0]]); ui->spinboxIndex1->blockSignals(false); ui->buttonAuto->blockSignals(true); ui->buttonAuto->setChecked(mAuto); ui->buttonAuto->blockSignals(false); ui->actionAutoIndividual->blockSignals(true); ui->actionAutoIndividual->setChecked(!mAutoCommon); ui->actionAutoIndividual->blockSignals(false); ui->actionAutoCommon->blockSignals(true); ui->actionAutoCommon->setChecked(mAutoCommon); ui->actionAutoCommon->blockSignals(false); ui->checkboxDB->blockSignals(true); ui->checkboxDB->setChecked(mDB); ui->checkboxDB->blockSignals(false); ui->widgetLegend->updateUi(); } /*! * \brief Устанавливает состояние сплиттера. * \param state Состояние сплиттера. */ void ArrayWidget::setSplitterState(const QByteArray &state) { ui->splitter->restoreState(state); } /*! * \brief Возвращает состояние сплиттера. * \return Состояние сплиттера. */ QByteArray ArrayWidget::splitterState() { return ui->splitter->saveState(); } /*! * \brief Устанавливает параметры списков провайдеров (минимум и макимум для синхронизации с легендой) и провайдеров (признак отображения). * \param scheme Параметры. */ void ArrayWidget::setProvidersScheme(const QByteArray &scheme) { QDataStream stream(const_cast<QByteArray *>(&scheme), QIODevice::ReadOnly); stream >> mMinimum >> mMaximum; foreach (auto providerList, mDataProvidersListsList) { if (!providerList.isEmpty()) { foreach (auto provider, providerList) { bool visible = provider->isVisible(); stream >> visible; provider->setVisible(visible); } (*providerList.begin())->setVisible(true); // Первый провайдер всегда видимый. } } updateView(); ui->widgetLegend->updateView(); ui->widgetLegend->updateUi(); } /*! * \brief Возвращает параметры списков провайдеров (минимум и макимум для синхронизации с легендой) и провайдеров (признак отображения). * \return Параметры. */ QByteArray ArrayWidget::providersScheme() { QByteArray scheme; QDataStream stream(&scheme, QIODevice::WriteOnly); stream << mMinimum << mMaximum; foreach (auto providerList, mDataProvidersListsList) { if (!providerList.isEmpty()) { foreach (auto provider, providerList) { bool visible = provider->isVisible(); stream << visible; } } } return scheme; } /*! * \brief Компонует строку, представляющую состав схемы scheme. * \param scheme Отображаемая схема. * \return Строка, представляющая состав схемы scheme. */ QString ArrayWidget::schemeToString(const QVariantList &scheme) { QString string; for (auto i = scheme.constBegin(); i != scheme.constEnd(); ) { string += i->toString(); ++ i; if (i != scheme.constEnd()) { string += ", "; } } return string; } /*! * \brief Компонует схему, представленную строкой string. * \param string Строка, представляющая состав схемы scheme. * \return Схема, представленная строкой string. */ QVariantList ArrayWidget::stringToScheme(const QString &string) { QVariantList scheme; QStringList strings = string.split(",", QString::SkipEmptyParts); for (auto i = strings.begin(); i != strings.end(); ++ i) { bool ok; int value = i->toInt(&ok); if (ok) { scheme << value; } } return scheme; } /*! * \brief Заполняет список провайдеров выбранного набора провайдеров. */ void ArrayWidget::getProviderList(QList<DataProvider *> &providerList) { if (0 <= mCurrentProviderListIndex && mCurrentProviderListIndex < mDataProvidersListsList.count()) { providerList = mDataProvidersListsList[mCurrentProviderListIndex]; } } /*! * \brief Выполняется при выборе провайдера данных из списка. * \param index Выбранный индекс. */ void ArrayWidget::on_comboboxProviders_currentIndexChanged(int index) { setCurrentProviderListIndex(index); } /*! * \brief Выполняется при изменении значения спинбокса индекса измерения 1. * \param value Новое значение. */ void ArrayWidget::on_spinboxIndex1_valueChanged(int value) { mCurrentIndexes[mDimensionsMap[0]] = value - mDimensionsBases[mDimensionsMap[0]]; updateView(); } /*! * \brief Выполняется при изменении значения спинбокса числа измерений 2. * \param value Новое значение. */ void ArrayWidget::on_spinboxDimension2Count_valueChanged(int value) { QVariantList scheme = mSchemes[mDimensionsMap[1]]; //// Добавление недостающих. value = qMin(value, mDimensionsBases[mDimensionsMap[1]] + mDimensionsCounts[mDimensionsMap[1]]); if (scheme.size() < value) { int last = (scheme.size() == 0) ? -1 : scheme.last().toInt(); for (int i = scheme.size(); i < value; i ++) { scheme.append(qMin(mDimensionsBases[mDimensionsMap[1]] + mDimensionsCounts[mDimensionsMap[1]] - 1, qMax(mDimensionsBases[mDimensionsMap[1]], ++ last))); } } //// Удаление лишних. if (scheme.size() > value) { for (int i = scheme.size(); i > value; i --) { scheme.removeLast(); } } setScheme(mDimensionsMap[1], scheme); } /*! * \brief Выполняется при завершении редактирования. */ void ArrayWidget::on_spinboxIndexes2_editingFinished() { QVariantList scheme = stringToScheme(ui->spinboxIndexes2->text()); setScheme(mDimensionsMap[1], scheme); } /*! * \brief Выполняется при изменении значения. * \param steps Значение изменения. */ void ArrayWidget::on_spinboxIndexes2_valueChanged(int steps) { QVariantList scheme = mSchemes[mDimensionsMap[1]]; for (auto i = scheme.begin(); i != scheme.end(); ++ i) { if (i->canConvert(QVariant::Int)) { *i = qMin(mDimensionsBases[mDimensionsMap[1]] + mDimensionsCounts[mDimensionsMap[1]] - 1, qMax(mDimensionsBases[mDimensionsMap[1]], i->toInt() + steps)); } } setScheme(mDimensionsMap[1], scheme); } /*! * \brief Выполняется при нажатии кнопки Авто. * \param checked Значение изменения. */ void ArrayWidget::on_buttonAuto_toggled(bool checked) { setAuto(checked); } /*! * \brief Выполняется при задании признака индивидуальных для каждого графика границ автоматического масштабирования. */ void ArrayWidget::on_actionAutoIndividual_triggered() { mAutoCommon = false; updateUi(); updateView(); } /*! * \brief Выполняется при задании признака общих для всех графиков границ автоматического масштабирования. */ void ArrayWidget::on_actionAutoCommon_triggered() { mAutoCommon = true; updateUi(); updateView(); } /*! * \brief Выполняется при нажатии чекбокса отображения в логарифмическом масштабе "дБ". * \param checked Значение изменения. */ void ArrayWidget::on_checkboxDB_clicked(bool checked) { setDB(checked); } /*! * \brief Выполняется при установке минимального значения. * \param min Минимальное значение. */ void ArrayWidget::on_widgetLegend_setMin(double value) { setMinimum(value); } /*! * \brief Выполняется при установке максимального значения. * \param max Максмимальное значение. */ void ArrayWidget::on_widgetLegend_setMax(double value) { setMaximum(value); } /*! * \brief Выполняется при запросе минимального значения. * \param value Возвращаемое минимальное значение. */ void ArrayWidget::on_widgetLegend_getMin(double &value) { value = mMinimum; } /*! * \brief Выполняется при запросе максимального значения. * \param value Возвращаемое максмимальное значение. */ void ArrayWidget::on_widgetLegend_getMax(double &value) { value = mMaximum; } /*! * \brief Выполняется при запросе значения признака отображения в дБ. * \param value Возвращаемое значение признака отображения в дБ. */ void ArrayWidget::on_widgetLegend_getdB(bool &value) { value = mDB; } /*! * \brief Выполняется при изменении списка отображаемых провайдеров данных. */ void ArrayWidget::on_widgetLegend_providersChanged() { updateView(); } /*! * \brief Выполняется при запросе виджетом легенды отображаемого списка провайдеров. Из списка исключается провайдер, используемый для отображения растра, т.к. он не отображаетсся на других графиках. * \param providerList Список провайдеров. */ void ArrayWidget::on_widgetLegend_getProviderList(QList<DataProvider *> &providerList) { getProviderList(providerList); if (!providerList.isEmpty()) { providerList.removeFirst(); } } /*! * \brief Устанавливает текст координат положения пикера на левом графике. * \param point Координаты положения пикера на графике. * \param text Координаты в текстовом формате. */ void ArrayWidget::on_plotDimension2_getTrackerText(const QPointF &point, QwtText &text) { text.setText(QString("%1, %2").arg(int(point.y() + 0.5)).arg(point.x())); } /*! * \brief Выполняется при закрытии набора графиков. */ void ArrayWidget::on_plotsetContainer_schemeChanged() { QVariantList scheme = ui->plotsetContainer->scheme(); ui->spinboxDimension2Count->setValue(scheme.size()); ui->spinboxIndexes2->setText(schemeToString(scheme)); } /*! * \brief Выполняется при необходимости инициализации набора графиков. * \param plotSet Набор графиков. */ void ArrayWidget::on_plotsetContainer_plotsetInitRequest(PlotSetWidget *plotSet) { if (!mDataProvidersListsList.isEmpty()) { QwtPlotItem *item = plotSet->plot(PlotSetWidget::PlotIDCentralPlot)->itemList().first(); //// Если есть провайдер, то добавляется спектрограмма. QwtPlotSpectrogram *spectrogram = new QwtPlotSpectrogram(); ColorMap *colorMap = new ColorMap; colorMap->setDefaultColor(palette().color(QPalette::Button)); colorMap->setGradientColors({Qt::darkBlue, Qt::blue, Qt::green, Qt::white, Qt::yellow, Qt::darkRed, Qt::red}); spectrogram->setColorMap(colorMap); spectrogram->setXAxis(QwtPlot::xTop); spectrogram->setYAxis(QwtPlot::yRight); spectrogram->setData(new ArrayRasterData()); plotSet->addPlotItem(spectrogram, PlotSetWidget::PlotIDCentralPlot, nullptr); //// item->setZ(plotSet->plot(PlotSetWidget::PlotIDCentralPlot)->itemList().last()->z() + 1); //// 0-й провайдер пропускается, т.к. он используется только для отображения цветового графика. Инициализация графиков с добавлением item-ов производится в обратном порядке для того, чтобы последний первый добавленный провайдер отображался поверх остальных. foreach (auto providerList, mDataProvidersListsList) { auto iterator = providerList.end(); for (-- iterator; iterator != providerList.begin(); -- iterator) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*iterator)) { //// Левый график. QwtPlotItem *plotItem = nullptr; if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *plotCurve = new QwtPlotCurve(); plotCurve->setPen(provider->color()); plotItem = plotCurve; } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *plotHistogram = new QwtPlotHistogram(); plotHistogram->setPen(provider->color()); plotHistogram->setBrush(provider->color()); plotItem = plotHistogram; } else { throw 0; } plotItem->setYAxis(QwtPlot::yLeft); plotSet->addPlotItem(plotItem, PlotSetWidget::PlotIDLeftPlot, provider); //// Нижний график. plotItem = nullptr; if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *plotCurve = new QwtPlotCurve(); plotCurve->setPen(provider->color()); plotItem = plotCurve; } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *plotHistogram = new QwtPlotHistogram(); plotHistogram->setPen(provider->color()); plotHistogram->setBrush(provider->color()); plotItem = plotHistogram; } else { throw 0; } plotItem->setXAxis(QwtPlot::xBottom); plotSet->addPlotItem(plotItem, PlotSetWidget::PlotIDBottomPlot, provider); } } } } connect(plotSet, &PlotSetWidget::centralPlotDrawForeground, this, &ArrayWidget::slot_centralPlot_drawForeground); connect(plotSet, &PlotSetWidget::leftPlotDrawBackground, this, &ArrayWidget::slot_leftPlot_drawBackground); connect(plotSet, &PlotSetWidget::leftPlotDrawForeground, this, &ArrayWidget::slot_leftPlot_drawForeground); connect(plotSet, &PlotSetWidget::bottomPlotDrawBackground, this, &ArrayWidget::slot_bottomPlot_drawBackground); connect(plotSet, &PlotSetWidget::bottomPlotDrawForeground, this, &ArrayWidget::slot_bottomPlot_drawForeground); } /*! * \brief Выполняется при необходимости обновления набора графиков. * \param plotSet Набор графиков. */ void ArrayWidget::on_plotsetContainer_plotsetUpdateRequest(PlotSetWidget *plotSet) { QList<DataProvider *> providerList; getProviderList(providerList); int dimension2Base = mDimensionsBases[mDimensionsMap[2]]; int dimension2Count = mDimensionsCounts[mDimensionsMap[2]]; int dimension3Base = mDimensionsBases[mDimensionsMap[3]]; int dimension3Count = mDimensionsCounts[mDimensionsMap[3]]; //// Формирование индексов в соответствии с отображаемыми размерностями. int index0 = mCurrentIndexes[mDimensionsMap[0]]; int index1 = plotSet->value().toInt() - mDimensionsBases[mDimensionsMap[1]]; int index2 = mCurrentIndexes[mDimensionsMap[2]]; int index3 = mCurrentIndexes[mDimensionsMap[3]]; //// Центральный график. int vectorCentral[DimensionCount]; vectorCentral[mDimensionsMap[0]] = index0; vectorCentral[mDimensionsMap[1]] = index1; vectorCentral[mDimensionsMap[2]] = -1; vectorCentral[mDimensionsMap[3]] = -1; //// Левый график. int vectorLeft[DimensionCount]; vectorLeft[mDimensionsMap[0]] = index0; vectorLeft[mDimensionsMap[1]] = index1; vectorLeft[mDimensionsMap[2]] = -1; vectorLeft[mDimensionsMap[3]] = index3; //// Нижний график. int vectorBottom[DimensionCount]; vectorBottom[mDimensionsMap[0]] = index0; vectorBottom[mDimensionsMap[1]] = index1; vectorBottom[mDimensionsMap[2]] = index2; vectorBottom[mDimensionsMap[3]] = -1; //// Центральный график. if (mFullUpdate) { double centralPlotMin = +FLT_MAX; double centralPlotMax = -FLT_MAX; if (!providerList.isEmpty()) { ArrayDataProvider *provider = static_cast<ArrayDataProvider *>(providerList.first()); if (mAuto) { if (provider != nullptr) { provider->minMax(centralPlotMin, centralPlotMax, vectorCentral[0], vectorCentral[1], vectorCentral[2], vectorCentral[3]); double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; centralPlotMin = pfunc(centralPlotMin); centralPlotMax = pfunc(centralPlotMax); } else { double (* pfunc)(double) = mDB ? todB_s : noop; centralPlotMin = pfunc(mMinimum); centralPlotMax = pfunc(mMaximum); } } else { double (* pfunc)(double) = mDB ? todB_s : noop; centralPlotMin = pfunc(mMinimum); centralPlotMax = pfunc(mMaximum); } checkMinMax(centralPlotMin, centralPlotMax); //// Заполнение данными. double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; QwtPlotSpectrogram *spectrogram = (QwtPlotSpectrogram *)plotSet->plotItem(PlotSetWidget::PlotIDCentralPlot, nullptr); ArrayRasterData *rasterData = static_cast<ArrayRasterData *>(spectrogram->data()); rasterData->setArrayRasterDataArg(provider, vectorCentral[mDimensionsMap[0]], vectorCentral[mDimensionsMap[1]], centralPlotMin, centralPlotMax, pfunc, mDimensionsMap[0], mDimensionsMap[1], mDimensionsMap[2], mDimensionsMap[3]); } //// Центральный график. double xyMin[DimensionCount]; double xyMax[DimensionCount]; xyMin[0] = xyMax[0] = mCurrentIndexes[0] - mDimensionsBases[0]; // Индексы отображаются в спинбоксе, не отображаются на графике. xyMin[1] = mDimensionsBases[1] - CurveMargin; xyMax[1] = mDimensionsBases[1] + mDimensionsCounts[1] - CurveMargin; xyMin[2] = mDimensionsBases[2] - CurveMargin; xyMax[2] = mDimensionsBases[2] + mDimensionsCounts[2] - CurveMargin; xyMin[3] = mDimensionsBases[3] - CurveMargin; xyMax[3] = mDimensionsBases[3] + mDimensionsCounts[3] - CurveMargin; double value2Min = xyMin[mDimensionsMap[2]]; double value2Max = xyMax[mDimensionsMap[2]]; double value3Min = xyMin[mDimensionsMap[3]]; double value3Max = xyMax[mDimensionsMap[3]]; emit mapCoordinate(mDimensionsMap[2], mDimensionUnitsVariants[mDimensionsMap[2]], xyMin[0], xyMin[1], xyMin[2], xyMin[3], value2Min); emit mapCoordinate(mDimensionsMap[2], mDimensionUnitsVariants[mDimensionsMap[2]], xyMax[0], xyMax[1], xyMax[2], xyMax[3], value2Max); emit mapCoordinate(mDimensionsMap[3], mDimensionUnitsVariants[mDimensionsMap[3]], xyMin[0], xyMin[1], xyMin[2], xyMin[3], value3Min); emit mapCoordinate(mDimensionsMap[3], mDimensionUnitsVariants[mDimensionsMap[3]], xyMax[0], xyMax[1], xyMax[2], xyMax[3], value3Max); QRectF rect1(xyMin[mDimensionsMap[3]], xyMin[mDimensionsMap[2]], xyMax[mDimensionsMap[3]] - xyMin[mDimensionsMap[3]], xyMax[mDimensionsMap[2]] - xyMin[mDimensionsMap[2]]); QRectF rect2(value3Min, value2Min, value3Max - value3Min, value2Max - value2Min); plotSet->setZoomBase(PlotSetWidget::PlotIDCentralPlot, rect1, rect2); plotSet->plot(PlotSetWidget::PlotIDCentralPlot)->replot(); } //// Заполнение данными. if (!providerList.isEmpty()) { if (index2 != -1 && index3 != -1) { //// Заполнение данными левого и нижнего графиков. std::vector<double> tmpx2(dimension2Count); std::vector<double> tmpy2(dimension2Count); std::vector<double> tmpx3(dimension3Count); std::vector<double> tmpy3(dimension3Count); //// Левый график. //// Заполнение фиксированной оси графика. for (int i = 0; i < dimension2Count; i ++) { tmpy2[i] = dimension2Base + i; } //// 0-й провайдер пропускается, т.к. он используется для отображения цветового графика. for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; provider->fetch(tmpx2.data(), pfunc, vectorLeft[0], vectorLeft[1], vectorLeft[2], vectorLeft[3]); if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(plotSet->plotItem(PlotSetWidget::PlotIDLeftPlot, provider)); curve->setSamples(tmpx2.data(), tmpy2.data(), dimension2Count); curve->setVisible(provider->isVisible()); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(plotSet->plotItem(PlotSetWidget::PlotIDLeftPlot, provider)); histogram->setSamples( nullptr); histogram->setVisible(false); } else { throw 0; } } } //// Нижний график. //// Заполнение фиксированной оси графика. for (int i = 0; i < dimension3Count; i ++) { tmpx3[i] = dimension3Base + i; } //// Заполнение данными. 0-й провайдер пропускается, т.к. он используется для отображения цветового графика. for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; provider->fetch(tmpy3.data(), pfunc, vectorBottom[0], vectorBottom[1], vectorBottom[2], vectorBottom[3]); if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(plotSet->plotItem(PlotSetWidget::PlotIDBottomPlot, provider)); curve->setSamples(tmpx3.data(), tmpy3.data(), dimension3Count); curve->setVisible(provider->isVisible()); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(plotSet->plotItem(PlotSetWidget::PlotIDBottomPlot, provider)); QVector<QwtIntervalSample> vector(dimension3Count); for (int i = 0; i < dimension3Count; i ++) { QwtInterval interval(i - 0.3, i + 0.3); interval.setBorderFlags(QwtInterval::ExcludeMaximum); vector[i] = QwtIntervalSample(tmpy3[i], interval); } histogram->setSamples(vector); histogram->setVisible(provider->isVisible()); } else { throw 0; } } } } else { //// Заполнение пустыми данными. //// 0-й провайдер пропускается, т.к. он используется для отображения цветового графика. for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { //// Левый график. if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(plotSet->plotItem(PlotSetWidget::PlotIDLeftPlot, provider)); curve->setSamples(nullptr, nullptr, 0); curve->setVisible(false); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(plotSet->plotItem(PlotSetWidget::PlotIDLeftPlot, provider)); histogram->setSamples(nullptr); histogram->setVisible(false); } else { throw 0; } //// Нижний график. if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(plotSet->plotItem(PlotSetWidget::PlotIDBottomPlot, provider)); curve->setSamples(nullptr, nullptr, 0); curve->setVisible(false); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(plotSet->plotItem(PlotSetWidget::PlotIDBottomPlot, provider)); histogram->setSamples(nullptr); histogram->setVisible(false); } else { throw 0; } } } } } //// Расчет минимумов и максимумов. double leftPlotMin = +FLT_MAX; double leftPlotMax = -FLT_MAX; double bottomPlotMin = +FLT_MAX; double bottomPlotMax = -FLT_MAX; if (mAuto) { if (!providerList.isEmpty() && index2 != -1 && index3 != -1) { //// Расчет минимума и максимума левого и нижнего графиков. /// 0-й провайдер пропускается, т.к. он используется для отображения цветового графика. for (auto i = ++ providerList.begin(); i != providerList.end(); ++ i) { if (auto *provider = dynamic_cast<ArrayDataProvider *>(*i)) { if (provider->isVisible()) { //// Левый график. if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(plotSet->plotItem(PlotSetWidget::PlotIDLeftPlot, provider)); leftPlotMin = std::min(leftPlotMin, curve->dataRect().left()); leftPlotMax = std::max(leftPlotMax, curve->dataRect().right()); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { double (* pfunc)(double) = mDB && !provider->isNodB() ? todB_s : noop; double min = +FLT_MAX; double max = -FLT_MAX; provider->minMax(min, max, vectorLeft[0], vectorLeft[1], vectorLeft[2], vectorLeft[3]); leftPlotMin = std::min(leftPlotMin, pfunc(min)); leftPlotMax = std::max(leftPlotMax, pfunc(max)); } else { throw 0; } //// Нижний график. if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeCurve) { QwtPlotCurve *curve = dynamic_cast<QwtPlotCurve *>(plotSet->plotItem(PlotSetWidget::PlotIDBottomPlot, provider)); bottomPlotMin = std::min(bottomPlotMin, curve->dataRect().top()); bottomPlotMax = std::max(bottomPlotMax, curve->dataRect().bottom()); } else if (provider->plotItemType() == ArrayDataProvider::PlotItemTypeHistogram) { QwtPlotHistogram *histogram = dynamic_cast<QwtPlotHistogram *>(plotSet->plotItem(PlotSetWidget::PlotIDBottomPlot, provider)); bottomPlotMin = std::min(bottomPlotMin, histogram->dataRect().top()); bottomPlotMax = std::max(bottomPlotMax, histogram->dataRect().bottom()); } else { throw 0; } } } } if (mAutoCommon) { leftPlotMin = bottomPlotMin = std::min(leftPlotMin, bottomPlotMin); leftPlotMax = bottomPlotMax = std::max(leftPlotMax, bottomPlotMax); } } else { double (* pfunc)(double) = mDB ? todB_s : noop; double min = pfunc(mMinimum); double max = pfunc(mMaximum); leftPlotMin = min; leftPlotMax = max; bottomPlotMin = min; bottomPlotMax = max; } } else { double (* pfunc)(double) = mDB ? todB_s : noop; double min = pfunc(mMinimum); double max = pfunc(mMaximum); leftPlotMin = min; leftPlotMax = max; bottomPlotMin = min; bottomPlotMax = max; } checkMinMax(leftPlotMin, leftPlotMax); checkMinMax(bottomPlotMin, bottomPlotMax); //// Установка осей графика. QRectF rect; //// Левый график. rect.setRect(leftPlotMin, dimension2Base - CurveMargin, leftPlotMax - leftPlotMin, dimension2Count); plotSet->setZoomBase(PlotSetWidget::PlotIDLeftPlot, rect, rect); //// Нижний график. rect.setRect(dimension3Base - CurveMargin, bottomPlotMin, dimension3Count, bottomPlotMax - bottomPlotMin); plotSet->setZoomBase(PlotSetWidget::PlotIDBottomPlot, rect, rect); //// Подписи к осям. QwtText title; title.setFont(mFont); //// Нижний график. if (index2 != -1) { title.setText(mDimensionsNames[mDimensionsMap[2]] + tr(" №") + QString::number(dimension2Base + index2)); } else { title.setText(QString()); } plotSet->plot(PlotSetWidget::PlotIDBottomPlot)->axisWidget(QwtPlot::xBottom)->setTitle(title); //// Левый график. if (index3 != -1) { title.setText(mDimensionsNames[mDimensionsMap[3]] + tr(" №") + QString::number(dimension3Base + index3)); } else { title.setText(QString()); } plotSet->plot(PlotSetWidget::PlotIDLeftPlot)->axisWidget(QwtPlot::yLeft)->setTitle(title); //// Перерисовка графиков. plotSet->plot(PlotSetWidget::PlotIDLeftPlot)->replot(); plotSet->plot(PlotSetWidget::PlotIDBottomPlot)->replot(); } /*! * \brief Выполняется при нажатии кнопок мыши в графике. * \param plotset Набор графиков. * \param plotId Идентификатор графика. * \param point Положение курсора в графике. * \param buttons Комбинация нажатых клавиш. */ void ArrayWidget::on_plotsetContainer_mousePress(PlotSetWidget *plotset, int plotId, QPointF point, Qt::MouseButtons buttons) { QList<DataProvider *> providerList; getProviderList(providerList); if (!providerList.isEmpty()) { if (buttons.testFlag(Qt::LeftButton) && !QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { //// Формирование индексов в соответствии с размерностями массива. if (plotset != nullptr) { mCurrentIndexes[mDimensionsMap[1]] = plotset->value().toInt() - mDimensionsBases[mDimensionsMap[1]]; } switch (plotId) { case PlotIDLeftLeftPlot: mCurrentIndexes[mDimensionsMap[1]] = (int)(point.y() + 0.5) - mDimensionsBases[mDimensionsMap[1]]; mCurrentIndexes[mDimensionsMap[1]] = std::max(0, std::min(mCurrentIndexes[mDimensionsMap[1]], mDimensionsCounts[mDimensionsMap[1]] - 1)); break; case PlotSetWidget::PlotIDCentralPlot: mCurrentIndexes[mDimensionsMap[2]] = (int)(point.y() + 0.5) - mDimensionsBases[mDimensionsMap[2]]; mCurrentIndexes[mDimensionsMap[3]] = (int)(point.x() + 0.5) - mDimensionsBases[mDimensionsMap[3]]; mCurrentIndexes[mDimensionsMap[2]] = std::max(0, std::min(mCurrentIndexes[mDimensionsMap[2]], mDimensionsCounts[mDimensionsMap[2]] - 1)); mCurrentIndexes[mDimensionsMap[3]] = std::max(0, std::min(mCurrentIndexes[mDimensionsMap[3]], mDimensionsCounts[mDimensionsMap[3]] - 1)); break; case PlotSetWidget::PlotIDLeftPlot: mCurrentIndexes[mDimensionsMap[2]] = (int)(point.y() + 0.5) - mDimensionsBases[mDimensionsMap[2]]; mCurrentIndexes[mDimensionsMap[2]] = std::max(0, std::min(mCurrentIndexes[mDimensionsMap[2]], mDimensionsCounts[mDimensionsMap[2]] - 1)); break; case PlotSetWidget::PlotIDBottomPlot: mCurrentIndexes[mDimensionsMap[3]] = (int)(point.x() + 0.5) - mDimensionsBases[mDimensionsMap[3]]; mCurrentIndexes[mDimensionsMap[3]] = std::max(0, std::min(mCurrentIndexes[mDimensionsMap[3]], mDimensionsCounts[mDimensionsMap[3]] - 1)); break; } mFullUpdate = false; updateView(); mFullUpdate = true; } } } /*! * \brief Выполняется при смещении курсора мыши в графике. * \param plotset Набор графиков. * \param plotId Идентификатор графика. * \param point Положение курсора в графике. * \param buttons Комбинация нажатых кнопок мыши. */ void ArrayWidget::on_plotsetContainer_mouseMove(PlotSetWidget *plotset, int plotId, QPointF point, Qt::MouseButtons buttons) { QList<DataProvider *> providerList; getProviderList(providerList); if (!providerList.isEmpty()) { ArrayDataProvider *provider = static_cast<ArrayDataProvider *>( providerList.first()); double (* pfunc)(double) = mDB ? todB_s : noop; //// Формирование индексов в соответствии с размерностями массива. int indexes[DimensionCount]; indexes[0] = mCurrentIndexes[0]; indexes[1] = mCurrentIndexes[1]; if (plotset != nullptr) { indexes[1] = plotset->value().toInt() - mDimensionsBases[1]; } indexes[2] = mCurrentIndexes[2]; indexes[3] = mCurrentIndexes[3]; switch (plotId) { case PlotIDLeftLeftPlot: indexes[mDimensionsMap[1]] = (int)(point.y() + 0.5) - mDimensionsBases[mDimensionsMap[1]]; indexes[mDimensionsMap[1]] = std::max(0, std::min(indexes[mDimensionsMap[1]], mDimensionsCounts[mDimensionsMap[1]] - 1)); break; case PlotSetWidget::PlotIDCentralPlot: indexes[mDimensionsMap[2]] = (int)(point.y() + 0.5) - mDimensionsBases[mDimensionsMap[2]]; indexes[mDimensionsMap[3]] = (int)(point.x() + 0.5) - mDimensionsBases[mDimensionsMap[3]]; indexes[mDimensionsMap[2]] = std::max(0, std::min(indexes[mDimensionsMap[2]], mDimensionsCounts[mDimensionsMap[2]] - 1)); indexes[mDimensionsMap[3]] = std::max(0, std::min(indexes[mDimensionsMap[3]], mDimensionsCounts[mDimensionsMap[3]] - 1)); break; case PlotSetWidget::PlotIDLeftPlot: indexes[mDimensionsMap[2]] = (int)(point.y() + 0.5) - mDimensionsBases[mDimensionsMap[2]]; indexes[mDimensionsMap[2]] = std::max(0, std::min(indexes[mDimensionsMap[2]], mDimensionsCounts[mDimensionsMap[2]] - 1)); break; case PlotSetWidget::PlotIDBottomPlot: indexes[mDimensionsMap[3]] = (int)(point.x() + 0.5) - mDimensionsBases[mDimensionsMap[3]]; indexes[mDimensionsMap[3]] = std::max(0, std::min(indexes[mDimensionsMap[3]], mDimensionsCounts[mDimensionsMap[3]] - 1)); break; } if (buttons.testFlag(Qt::LeftButton) && !QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) { mCurrentIndexes[0] = indexes[0]; mCurrentIndexes[1] = indexes[1]; mCurrentIndexes[2] = indexes[2]; mCurrentIndexes[3] = indexes[3]; mFullUpdate = false; updateView(); mFullUpdate = true; } //// Пересчет индексов в значения. if (indexes[0] != -1) { double value = NoAxisMapping; emit mapCoordinate(0, mDimensionUnitsVariants[0], indexes[0], indexes[1], indexes[2], indexes[3], value); QString text = mDimensionsNames[0] + ": " + QString::number(mDimensionsBases[0] + indexes[0]); if (value != NoAxisMapping) { text += "(" + QString::number(value, 'f', 1); if (0 <= mDimensionUnitsVariants[0] && mDimensionUnitsVariants[0] < mDimensionsUnits[0].count()) { text += " " + mDimensionsUnits[0][mDimensionUnitsVariants[0]]; } text += ")"; if (mDimensionsUnits[0].count() > 1) { text += "\u25BC"; } } ui->labelIndex1->setText(text); } else { ui->labelIndex1->setText(QString()); } if (indexes[1] != -1) { double value = NoAxisMapping; emit mapCoordinate(1, mDimensionUnitsVariants[1], indexes[0], indexes[1], indexes[2], indexes[3], value); QString text = mDimensionsNames[1] + ": " + QString::number(mDimensionsBases[1] + indexes[1]); if (value != NoAxisMapping) { text += "(" + QString::number(value, 'f', 1); if (0 <= mDimensionUnitsVariants[1] && mDimensionUnitsVariants[1] < mDimensionsUnits[1].count()) { text += " " + mDimensionsUnits[1][mDimensionUnitsVariants[1]]; } text += ")"; if (mDimensionsUnits[1].count() > 1) { text += "\u25BC"; } } ui->labelIndex2->setText(text); } else { ui->labelIndex2->setText(QString()); } if (indexes[2] != -1) { double value = NoAxisMapping; emit mapCoordinate(2, mDimensionUnitsVariants[2], indexes[0], indexes[1], indexes[2], indexes[3], value); QString text = mDimensionsNames[2] + ": " + QString::number(mDimensionsBases[2] + indexes[2]); if (value != NoAxisMapping) { text += "(" + QString::number(value, 'f', 1); if (0 <= mDimensionUnitsVariants[2] && mDimensionUnitsVariants[2] < mDimensionsUnits[2].count()) { text += " " + mDimensionsUnits[2][mDimensionUnitsVariants[2]]; } text += ")"; if (mDimensionsUnits[2].count() > 1) { text += "\u25BC"; } } ui->labelIndex3->setText(text); } else { ui->labelIndex3->setText(QString()); } if (indexes[3] != -1) { double value = NoAxisMapping; emit mapCoordinate(3, mDimensionUnitsVariants[3], indexes[0], indexes[1], indexes[2], indexes[3], value); QString text = mDimensionsNames[3] + ": " + QString::number(mDimensionsBases[3] + indexes[3]); if (value != NoAxisMapping) { text += "(" + QString::number(value, 'f', 1); if (0 <= mDimensionUnitsVariants[3] && mDimensionUnitsVariants[3] < mDimensionsUnits[3].count()) { text += " " + mDimensionsUnits[3][mDimensionUnitsVariants[3]]; } text += ")"; if (mDimensionsUnits[3].count() > 1) { text += "\u25BC"; } } ui->labelIndex4->setText(text); } else { ui->labelIndex4->setText(QString()); } double value = provider->value(indexes[0], indexes[1], indexes[2], indexes[3]); if (value != FLT_MAX) { ui->labelValue->setText(QString::number(pfunc(value))); } else { ui->labelValue->setText(QString()); } QString text; emit describeCoordinate(indexes[0], indexes[1], indexes[2], indexes[3], text); ui->labelText->setText(text); } } /*! * \brief Выполняется при отжатии кнопок мыши в графике. * \param plotset Набор графиков. * \param plotId Идентификатор графика. * \param point Положение курсора в графике. * \param buttons Комбинация нажатых клавиш. */ void ArrayWidget::on_plotsetContainer_mouseRelease(PlotSetWidget *plotset, int plotId, QPointF point, Qt::MouseButtons buttons) { Q_UNUSED(plotset) Q_UNUSED(plotId) Q_UNUSED(point) Q_UNUSED(buttons) } /*! * \brief Возвращает признак отображения панели информации. * \return Признак отображения панели информации. */ bool ArrayWidget::isInfoVisible() { return ui->labelInformation->isVisible(); } /*! * \brief Показывает/скрывает панель информации. * \param visible Признак отображения панели информации. */ void ArrayWidget::setInfoPanelVisible(bool visible) { ui->labelInformation->setVisible(visible); ui->buttonHideInfo->setVisible(visible); ui->buttonShowInfo->setVisible(!visible); } /*! * \brief Устанавливает высоту панели отображения информации. * \param height Высота панели отображения информации в пикселах. */ void ArrayWidget::setInfoPanelHeight(int height) { ui->labelInformation->setMinimumHeight(height); ui->labelInformation->setMaximumHeight(height); } /*! * \brief Возвращает индекс под курсором для измерения dimension. * \param dimension Номер измерения. * \return Индекс под курсором для измерения dimension. */ int ArrayWidget::currentIndex(int dimension) { return mCurrentIndexes[mDimensionsMap[dimension]]; } /*! * \brief Выполняется при нажатии кнопки скрытия панели информации. */ void ArrayWidget::on_buttonHideInfo_clicked() { setInfoPanelVisible(false); } /*! * \brief Выполняется при нажатии кнопки отображения панели информации. */ void ArrayWidget::on_buttonShowInfo_clicked() { setInfoPanelVisible(true); } /*! * \brief Выполняется при выборе пункта меню единиц измерения 1. * \param action Выбранный пункт меню. */ void ArrayWidget::slot_menuDimension1_triggered(QAction *action) { int variant = action->data().toInt(); mDimensionUnitsVariants[0] = variant; updateView(); // Обновление шкал графиков. } /*! * \brief Выполняется при выборе пункта меню единиц измерения 2. * \param action Выбранный пункт меню. */ void ArrayWidget::slot_menuDimension2_triggered(QAction *action) { int variant = action->data().toInt(); mDimensionUnitsVariants[1] = variant; updateView(); // Обновление шкал графиков. } /*! * \brief Выполняется при выборе пункта меню единиц измерения 3. * \param action Выбранный пункт меню. */ void ArrayWidget::slot_menuDimension3_triggered(QAction *action) { int variant = action->data().toInt(); mDimensionUnitsVariants[2] = variant; updateView(); // Обновление шкал графиков. } /*! * \brief Выполняется при выборе пункта меню единиц измерения 4. * \param action Выбранный пункт меню. */ void ArrayWidget::slot_menuDimension4_triggered(QAction *action) { int variant = action->data().toInt(); mDimensionUnitsVariants[3] = variant; updateView(); // Обновление шкал графиков. } /*! * \brief Выполняется при нажатии кнопки вращения гафиков. */ void ArrayWidget::on_buttonRotate_clicked() { std::vector<int> map = mDimensionsMap; qSwap(map[2], map[3]); setDimensionsMap(map); } /*! * \brief Выполняется при выборе пункта "Вращение" выпадающего меню кнопки "Вращение". */ void ArrayWidget::on_actionRotate2_triggered() { std::vector<int> map = mDimensionsMap; qSwap(map[1], map[2]); setDimensionsMap(map); } /*! * \brief Выполняется при выборе пункта "Сброс вращения" выпадающего меню кнопки "Вращение". */ void ArrayWidget::on_actionRotateReset_triggered() { std::vector<int> map = mDimensionsMap; map[0] = 0; map[1] = 1; map[2] = 2; map[3] = 3; setDimensionsMap(map); } /*! * \brief Выполняется при перерисовке заднего плана левого левого графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_leftLeftPlot_drawBackground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotBackground(PlotIDLeftLeftPlot, painter, xMap, yMap, canvasRect); } /*! * \brief Выполняется при перерисовке заднего плана левого графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_leftPlot_drawBackground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotBackground(PlotIDLeftPlot, painter, xMap, yMap, canvasRect); } /*! * \brief Выполняется при перерисовке заднего плана нижнего графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_bottomPlot_drawBackground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotBackground(PlotIDBottomPlot, painter, xMap, yMap, canvasRect); } /*! * \brief Выполняется при перерисовке переднего плана левого левого графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_leftLeftPlot_drawForeground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotForeground(PlotIDLeftLeftPlot, painter, xMap, yMap, canvasRect); } /*! * \brief Выполняется при перерисовке переднего плана центрального графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_centralPlot_drawForeground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotForeground(PlotIDCentralPlot, painter, xMap, yMap, canvasRect); } /*! * \brief Выполняется при перерисовке переднего плана левого графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_leftPlot_drawForeground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotForeground(PlotIDLeftPlot, painter, xMap, yMap, canvasRect); } /*! * \brief Выполняется при перерисовке переднего плана нижнего графика. * \param painter Объект рисования. * \param xMap Объект отображения координат оси x. * \param yMap Объект отображения координат оси y. * \param canvasRect Координаты области рисования. */ void ArrayWidget::slot_bottomPlot_drawForeground(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &canvasRect) { emit drawPlotForeground(PlotIDBottomPlot, painter, xMap, yMap, canvasRect); }