@@ -0,0 +1,26 | |||
|
1 | include_directories(include) | |
|
2 | FILE (GLOB_RECURSE python_providers | |
|
3 | include/*.h | |
|
4 | src/*.cpp | |
|
5 | resources/*.qrc | |
|
6 | ) | |
|
7 | ||
|
8 | add_definitions(-DQT_PLUGIN) | |
|
9 | add_definitions(-DSCIQLOP_PLUGIN_JSON_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/python_providers.json") | |
|
10 | if(NOT BUILD_SHARED_LIBS) | |
|
11 | add_definitions(-DQT_STATICPLUGIN) | |
|
12 | endif() | |
|
13 | ||
|
14 | add_library(python_providers ${python_providers}) | |
|
15 | SET_TARGET_PROPERTIES(python_providers PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) | |
|
16 | ||
|
17 | target_link_libraries(python_providers PUBLIC sciqlopgui) | |
|
18 | target_link_libraries(python_providers PRIVATE pybind11::embed) | |
|
19 | ADD_DEFINITIONS(-DQT_NO_KEYWORDS) | |
|
20 | install(TARGETS python_providers | |
|
21 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop | |
|
22 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop | |
|
23 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | |
|
24 | ||
|
25 | include(sciqlop_tests) | |
|
26 |
@@ -0,0 +1,25 | |||
|
1 | #ifndef PYTHON_PROVIDERS_H | |
|
2 | #define PYTHON_PROVIDERS_H | |
|
3 | ||
|
4 | #include <Plugin/IPlugin.h> | |
|
5 | ||
|
6 | ||
|
7 | #include <memory> | |
|
8 | ||
|
9 | #ifndef SCIQLOP_PLUGIN_JSON_FILE_PATH | |
|
10 | #define SCIQLOP_PLUGIN_JSON_FILE_PATH "python_providers.json" | |
|
11 | #endif | |
|
12 | ||
|
13 | class DataSourceItem; | |
|
14 | ||
|
15 | class PythonProviders : public QObject, public IPlugin | |
|
16 | { | |
|
17 | Q_OBJECT | |
|
18 | Q_INTERFACES(IPlugin) | |
|
19 | Q_PLUGIN_METADATA(IID "sciqlop.plugin.IPlugin" FILE SCIQLOP_PLUGIN_JSON_FILE_PATH) | |
|
20 | public: | |
|
21 | /// @sa IPlugin::initialize() | |
|
22 | void initialize() override; | |
|
23 | }; | |
|
24 | ||
|
25 | #endif // PYTHON_PROVIDERS_H |
@@ -0,0 +1,9 | |||
|
1 | #include "python_providers.h" | |
|
2 | #include <pybind11/embed.h> | |
|
3 | namespace py = pybind11; | |
|
4 | ||
|
5 | void PythonProviders::initialize() | |
|
6 | { | |
|
7 | py::scoped_interpreter guard {}; | |
|
8 | py::print("Hello, World!"); | |
|
9 | } |
@@ -1,41 +1,42 | |||
|
1 | 1 | include_directories(include) |
|
2 | 2 | |
|
3 | 3 | FILE (GLOB_RECURSE app_SRCS |
|
4 | 4 | include/*.h |
|
5 | 5 | src/*.cpp |
|
6 | 6 | resources/*.qrc |
|
7 | 7 | ) |
|
8 | 8 | |
|
9 | 9 | QT5_WRAP_UI(UiGenerated_SRCS |
|
10 | 10 | ui/MainWindow.ui |
|
11 | 11 | ) |
|
12 | 12 | |
|
13 | 13 | add_executable(sciqlopapp WIN32 ${app_SRCS} ${UiGenerated_SRCS}) |
|
14 | 14 | if(NOT BUILD_SHARED_LIBS) |
|
15 | 15 | add_definitions(-DQT_STATICPLUGIN) |
|
16 | 16 | if(BUILD_PLUGINS) |
|
17 | 17 | target_link_libraries(sciqlopapp mockplugin) |
|
18 | target_link_libraries(sciqlopapp amdaplugin) | |
|
18 | #target_link_libraries(sciqlopapp amdaplugin) | |
|
19 | target_link_libraries(sciqlopapp python_providers) | |
|
19 | 20 | endif() |
|
20 | 21 | endif() |
|
21 | 22 | |
|
22 | 23 | if(NOT BUILD_PLUGINS) |
|
23 | 24 | add_definitions(-DSQP_NO_PLUGINS) |
|
24 | 25 | endif() |
|
25 | 26 | |
|
26 | 27 | target_link_libraries(sciqlopapp |
|
27 | 28 | Qt5::Core |
|
28 | 29 | Qt5::Widgets |
|
29 | 30 | Qt5::Network |
|
30 | 31 | Qt5::PrintSupport |
|
31 | 32 | Qt5::Svg |
|
32 | 33 | sciqlopgui |
|
33 | 34 | sciqlopcore |
|
34 | 35 | ) |
|
35 | 36 | |
|
36 | 37 | install(TARGETS sciqlopapp DESTINATION ${CMAKE_INSTALL_BINDIR}) |
|
37 | 38 | install(FILES resources/SciQLOP.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications/) |
|
38 | 39 | install(FILES resources/SciQLOP.appdata.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo/) |
|
39 | 40 | install(FILES resources/sciqlopLOGO.svg DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/SciQLOP/icons/) |
|
40 | 41 | |
|
41 | 42 |
@@ -1,99 +1,100 | |||
|
1 | 1 | /*------------------------------------------------------------------------------ |
|
2 | 2 | -- This file is a part of the QLop Software |
|
3 | 3 | -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS |
|
4 | 4 | -- |
|
5 | 5 | -- This program is free software; you can redistribute it and/or modify |
|
6 | 6 | -- it under the terms of the GNU General Public License as published by |
|
7 | 7 | -- the Free Software Foundation; either version 2 of the License, or |
|
8 | 8 | -- (at your option) any later version. |
|
9 | 9 | -- |
|
10 | 10 | -- This program is distributed in the hope that it will be useful, |
|
11 | 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | 13 | -- GNU General Public License for more details. |
|
14 | 14 | -- |
|
15 | 15 | -- You should have received a copy of the GNU General Public License |
|
16 | 16 | -- along with this program; if not, write to the Free Software |
|
17 | 17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 | 18 | -------------------------------------------------------------------------------*/ |
|
19 | 19 | /*-- Author : Alexis Jeandet |
|
20 | 20 | -- Mail : alexis.jeandet@member.fsf.org |
|
21 | 21 | ----------------------------------------------------------------------------*/ |
|
22 | 22 | #include "MainWindow.h" |
|
23 | 23 | #include <QProcessEnvironment> |
|
24 | 24 | #include <QThread> |
|
25 | 25 | #include <SqpApplication.h> |
|
26 | 26 | #include <qglobal.h> |
|
27 | 27 | |
|
28 | 28 | #include <PluginManager/PluginManager.h> |
|
29 | 29 | #include <QDir> |
|
30 | 30 | #include <QtPlugin> |
|
31 | 31 | |
|
32 | 32 | #include <QLoggingCategory> |
|
33 | 33 | |
|
34 | 34 | Q_LOGGING_CATEGORY(LOG_Main, "Main") |
|
35 | 35 | |
|
36 | 36 | namespace |
|
37 | 37 | { |
|
38 | 38 | |
|
39 | 39 | const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins"); |
|
40 | 40 | |
|
41 | 41 | |
|
42 | 42 | } // namespace |
|
43 | 43 | |
|
44 | 44 | int main(int argc, char* argv[]) |
|
45 | 45 | { |
|
46 | 46 | #ifdef QT_STATICPLUGIN |
|
47 | 47 | #ifndef SQP_NO_PLUGINS |
|
48 | 48 | Q_IMPORT_PLUGIN(MockPlugin) |
|
49 |
Q_IMPORT_PLUGIN( |
|
|
50 | Q_INIT_RESOURCE(amdaresources); | |
|
49 | Q_IMPORT_PLUGIN(PythonProviders) | |
|
50 | // Q_IMPORT_PLUGIN(AmdaPlugin) | |
|
51 | // Q_INIT_RESOURCE(amdaresources); | |
|
51 | 52 | #endif |
|
52 | 53 | #endif |
|
53 | 54 | Q_INIT_RESOURCE(sqpguiresources); |
|
54 | 55 | |
|
55 | 56 | SqpApplication::setOrganizationName("LPP"); |
|
56 | 57 | SqpApplication::setOrganizationDomain("lpp.fr"); |
|
57 | 58 | SqpApplication::setApplicationName("SciQLop"); |
|
58 | 59 | |
|
59 | 60 | QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); |
|
60 | 61 | |
|
61 | 62 | SqpApplication a { argc, argv }; |
|
62 | 63 | |
|
63 | 64 | MainWindow w; |
|
64 | 65 | w.show(); |
|
65 | 66 | |
|
66 | 67 | // Loads plugins |
|
67 | 68 | auto pluginDir = QDir { a.applicationDirPath() }; |
|
68 | 69 | auto pluginLookupPath = { |
|
69 | 70 | #if _WIN32 || _WIN64 |
|
70 | 71 | a.applicationDirPath() + "/SciQLop" |
|
71 | 72 | #else |
|
72 | 73 | a.applicationDirPath() + "/../lib64/SciQLop", |
|
73 | 74 | a.applicationDirPath() + "/../lib64/sciqlop", |
|
74 | 75 | a.applicationDirPath() + "/../lib/SciQLop", |
|
75 | 76 | a.applicationDirPath() + "/../lib/sciqlop", |
|
76 | 77 | #endif |
|
77 | 78 | }; |
|
78 | 79 | |
|
79 | 80 | #if _WIN32 || _WIN64 |
|
80 | 81 | pluginDir.mkdir(PLUGIN_DIRECTORY_NAME); |
|
81 | 82 | pluginDir.cd(PLUGIN_DIRECTORY_NAME); |
|
82 | 83 | #endif |
|
83 | 84 | |
|
84 | 85 | PluginManager pluginManager {}; |
|
85 | 86 | |
|
86 | 87 | for (auto&& path : pluginLookupPath) |
|
87 | 88 | { |
|
88 | 89 | QDir directory { path }; |
|
89 | 90 | if (directory.exists()) |
|
90 | 91 | { |
|
91 | 92 | qCDebug(LOG_Main()) |
|
92 | 93 | << QObject::tr("Plugin directory: %1").arg(directory.absolutePath()); |
|
93 | 94 | pluginManager.loadPlugins(directory); |
|
94 | 95 | } |
|
95 | 96 | } |
|
96 | 97 | pluginManager.loadStaticPlugins(); |
|
97 | 98 | |
|
98 | 99 | return a.exec(); |
|
99 | 100 | } |
@@ -1,395 +1,395 | |||
|
1 | 1 | /*------------------------------------------------------------------------------ |
|
2 | 2 | -- This file is a part of the SciQLop Software |
|
3 | 3 | -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS |
|
4 | 4 | -- |
|
5 | 5 | -- This program is free software; you can redistribute it and/or modify |
|
6 | 6 | -- it under the terms of the GNU General Public License as published by |
|
7 | 7 | -- the Free Software Foundation; either version 2 of the License, or |
|
8 | 8 | -- (at your option) any later version. |
|
9 | 9 | -- |
|
10 | 10 | -- This program is distributed in the hope that it will be useful, |
|
11 | 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | 13 | -- GNU General Public License for more details. |
|
14 | 14 | -- |
|
15 | 15 | -- You should have received a copy of the GNU General Public License |
|
16 | 16 | -- along with this program; if not, write to the Free Software |
|
17 | 17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 | 18 | -------------------------------------------------------------------------------*/ |
|
19 | 19 | /*-- Author : Alexis Jeandet |
|
20 | 20 | -- Mail : alexis.jeandet@member.fsf.org |
|
21 | 21 | ----------------------------------------------------------------------------*/ |
|
22 | 22 | #include "MainWindow.h" |
|
23 | 23 | #include "ui_MainWindow.h" |
|
24 | 24 | |
|
25 | 25 | #include <Catalogue/CatalogueController.h> |
|
26 | 26 | //#include <Catalogue/CatalogueExplorer.h> |
|
27 | 27 | #include <DataSource/DataSourceController.h> |
|
28 | 28 | #include <DataSource/DataSourceWidget.h> |
|
29 | 29 | #include <Settings/SqpSettingsDialog.h> |
|
30 | 30 | #include <Settings/SqpSettingsGeneralWidget.h> |
|
31 | 31 | #include <SidePane/SqpSidePane.h> |
|
32 | 32 | #include <SqpApplication.h> |
|
33 | 33 | #include <Time/TimeController.h> |
|
34 | 34 | #include <TimeWidget/TimeWidget.h> |
|
35 | 35 | #include <Visualization/VisualizationController.h> |
|
36 | 36 | |
|
37 | 37 | #include <QAction> |
|
38 | 38 | #include <QCloseEvent> |
|
39 | 39 | #include <QDate> |
|
40 | 40 | #include <QDir> |
|
41 | 41 | #include <QFileDialog> |
|
42 | 42 | #include <QMessageBox> |
|
43 | 43 | #include <QToolBar> |
|
44 | 44 | #include <QToolButton> |
|
45 | 45 | #include <memory.h> |
|
46 | 46 | |
|
47 | 47 | #include "iostream" |
|
48 | 48 | |
|
49 | 49 | Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow") |
|
50 | 50 | |
|
51 | 51 | namespace |
|
52 | 52 | { |
|
53 | 53 | const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0; |
|
54 | 54 | const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1; |
|
55 | 55 | const auto VIEWPLITTERINDEX = 2; |
|
56 | 56 | const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3; |
|
57 | 57 | const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4; |
|
58 | 58 | } |
|
59 | 59 | |
|
60 | 60 | class MainWindow::MainWindowPrivate |
|
61 | 61 | { |
|
62 | 62 | public: |
|
63 | 63 | explicit MainWindowPrivate(MainWindow* mainWindow) |
|
64 | 64 | : m_LastOpenLeftInspectorSize {} |
|
65 | 65 | , m_LastOpenRightInspectorSize {} |
|
66 | 66 | , m_GeneralSettingsWidget { new SqpSettingsGeneralWidget { mainWindow } } |
|
67 | 67 | , m_SettingsDialog { new SqpSettingsDialog { mainWindow } } |
|
68 | 68 | //, m_CatalogExplorer { new CatalogueExplorer { mainWindow } } |
|
69 | 69 | { |
|
70 | 70 | } |
|
71 | 71 | |
|
72 | 72 | QSize m_LastOpenLeftInspectorSize; |
|
73 | 73 | QSize m_LastOpenRightInspectorSize; |
|
74 | 74 | /// General settings widget. MainWindow has the ownership |
|
75 | 75 | SqpSettingsGeneralWidget* m_GeneralSettingsWidget; |
|
76 | 76 | /// Settings dialog. MainWindow has the ownership |
|
77 | 77 | SqpSettingsDialog* m_SettingsDialog; |
|
78 | 78 | /// Catalogue dialog. MainWindow has the ownership |
|
79 | 79 | // CatalogueExplorer* m_CatalogExplorer; |
|
80 | 80 | |
|
81 | 81 | bool checkDataToSave(QWidget* parentWidget); |
|
82 | 82 | }; |
|
83 | 83 | |
|
84 | 84 | MainWindow::MainWindow(QWidget* parent) |
|
85 | 85 | : QMainWindow { parent } |
|
86 | 86 | , m_Ui { new Ui::MainWindow } |
|
87 | 87 | , impl { spimpl::make_unique_impl<MainWindowPrivate>(this) } |
|
88 | 88 | { |
|
89 | 89 | m_Ui->setupUi(this); |
|
90 | 90 | |
|
91 | 91 | m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false); |
|
92 | 92 | m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false); |
|
93 | 93 | |
|
94 | 94 | // impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view); |
|
95 | 95 | |
|
96 | 96 | |
|
97 | 97 | auto spacerLeftTop = new QWidget {}; |
|
98 | 98 | spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
99 | 99 | |
|
100 | 100 | auto spacerLeftBottom = new QWidget {}; |
|
101 | 101 | spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
102 | 102 | |
|
103 | 103 | |
|
104 | 104 | auto spacerRightTop = new QWidget {}; |
|
105 | 105 | spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
106 | 106 | |
|
107 | 107 | auto spacerRightBottom = new QWidget {}; |
|
108 | 108 | spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
109 | 109 | |
|
110 | 110 | |
|
111 | 111 | auto openInspector = [this](bool checked, bool right, auto action) { |
|
112 | 112 | action->setIcon( |
|
113 | 113 | QIcon { (checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png" }); |
|
114 | 114 | |
|
115 | 115 | auto& lastInspectorSize |
|
116 | 116 | = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize; |
|
117 | 117 | |
|
118 | 118 | auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size() |
|
119 | 119 | : m_Ui->leftMainInspectorWidget->size(); |
|
120 | 120 | |
|
121 | 121 | // Update of the last opened geometry |
|
122 | 122 | if (checked) |
|
123 | 123 | { |
|
124 | 124 | lastInspectorSize = nextInspectorSize; |
|
125 | 125 | } |
|
126 | 126 | |
|
127 | 127 | auto startSize = lastInspectorSize; |
|
128 | 128 | auto endSize = startSize; |
|
129 | 129 | endSize.setWidth(0); |
|
130 | 130 | |
|
131 | 131 | auto splitterInspectorIndex |
|
132 | 132 | = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX; |
|
133 | 133 | |
|
134 | 134 | auto currentSizes = m_Ui->splitter->sizes(); |
|
135 | 135 | if (checked) |
|
136 | 136 | { |
|
137 | 137 | // adjust sizes individually here, e.g. |
|
138 | 138 | currentSizes[splitterInspectorIndex] -= lastInspectorSize.width(); |
|
139 | 139 | currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width(); |
|
140 | 140 | m_Ui->splitter->setSizes(currentSizes); |
|
141 | 141 | } |
|
142 | 142 | else |
|
143 | 143 | { |
|
144 | 144 | // adjust sizes individually here, e.g. |
|
145 | 145 | currentSizes[splitterInspectorIndex] += lastInspectorSize.width(); |
|
146 | 146 | currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width(); |
|
147 | 147 | m_Ui->splitter->setSizes(currentSizes); |
|
148 | 148 | } |
|
149 | 149 | }; |
|
150 | 150 | |
|
151 | 151 | |
|
152 | 152 | // //////////////// // |
|
153 | 153 | // Menu and Toolbar // |
|
154 | 154 | // //////////////// // |
|
155 | 155 | this->menuBar()->addAction(tr("File")); |
|
156 | 156 | auto toolsMenu = this->menuBar()->addMenu(tr("Tools")); |
|
157 | 157 | toolsMenu->addAction(tr("Settings..."), [this]() { |
|
158 | 158 | // Loads settings |
|
159 | 159 | impl->m_SettingsDialog->loadSettings(); |
|
160 | 160 | |
|
161 | 161 | // Open settings dialog and save settings if the dialog is accepted |
|
162 | 162 | if (impl->m_SettingsDialog->exec() == QDialog::Accepted) |
|
163 | 163 | { |
|
164 | 164 | impl->m_SettingsDialog->saveSettings(); |
|
165 | 165 | } |
|
166 | 166 | }); |
|
167 | 167 | |
|
168 | 168 | auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar")); |
|
169 | 169 | |
|
170 | 170 | auto timeWidget = new TimeWidget {}; |
|
171 | 171 | mainToolBar->addWidget(timeWidget); |
|
172 | 172 | |
|
173 | 173 | // Interaction modes |
|
174 | 174 | auto actionPointerMode = new QAction { QIcon(":/icones/pointer.png"), "Move", this }; |
|
175 | 175 | actionPointerMode->setCheckable(true); |
|
176 | 176 | actionPointerMode->setChecked( |
|
177 | 177 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None); |
|
178 | 178 | connect(actionPointerMode, &QAction::triggered, |
|
179 | 179 | []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); }); |
|
180 | 180 | |
|
181 | 181 | auto actionZoomMode = new QAction { QIcon(":/icones/zoom.png"), "Zoom", this }; |
|
182 | 182 | actionZoomMode->setCheckable(true); |
|
183 | 183 | actionZoomMode->setChecked( |
|
184 | 184 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox); |
|
185 | 185 | connect(actionZoomMode, &QAction::triggered, |
|
186 | 186 | []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox); }); |
|
187 | 187 | |
|
188 | 188 | auto actionOrganisationMode = new QAction { QIcon(":/icones/drag.png"), "Organize", this }; |
|
189 | 189 | actionOrganisationMode->setCheckable(true); |
|
190 | 190 | actionOrganisationMode->setChecked( |
|
191 | 191 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop); |
|
192 | 192 | connect(actionOrganisationMode, &QAction::triggered, []() { |
|
193 | 193 | sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop); |
|
194 | 194 | }); |
|
195 | 195 | |
|
196 | 196 | auto actionZonesMode = new QAction { QIcon(":/icones/rectangle.png"), "Zones", this }; |
|
197 | 197 | actionZonesMode->setCheckable(true); |
|
198 | 198 | actionZonesMode->setChecked( |
|
199 | 199 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones); |
|
200 | 200 | connect(actionZonesMode, &QAction::triggered, []() { |
|
201 | 201 | sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones); |
|
202 | 202 | }); |
|
203 | 203 | |
|
204 | 204 | auto modeActionGroup = new QActionGroup { this }; |
|
205 | 205 | modeActionGroup->addAction(actionZoomMode); |
|
206 | 206 | modeActionGroup->addAction(actionZonesMode); |
|
207 | 207 | modeActionGroup->addAction(actionOrganisationMode); |
|
208 | 208 | modeActionGroup->addAction(actionPointerMode); |
|
209 | 209 | modeActionGroup->setExclusive(true); |
|
210 | 210 | |
|
211 | 211 | mainToolBar->addSeparator(); |
|
212 | 212 | mainToolBar->addAction(actionPointerMode); |
|
213 | 213 | mainToolBar->addAction(actionZoomMode); |
|
214 | 214 | mainToolBar->addAction(actionOrganisationMode); |
|
215 | 215 | mainToolBar->addAction(actionZonesMode); |
|
216 | 216 | mainToolBar->addSeparator(); |
|
217 | 217 | |
|
218 | 218 | // Cursors |
|
219 | 219 | auto btnCursor = new QToolButton { this }; |
|
220 | 220 | btnCursor->setIcon(QIcon(":/icones/cursor.png")); |
|
221 | 221 | btnCursor->setText("Cursor"); |
|
222 | 222 | btnCursor->setToolTip("Cursor"); |
|
223 | 223 | btnCursor->setPopupMode(QToolButton::InstantPopup); |
|
224 | 224 | auto cursorMenu = new QMenu("CursorMenu", this); |
|
225 | 225 | btnCursor->setMenu(cursorMenu); |
|
226 | 226 | |
|
227 | 227 | auto noCursorAction = cursorMenu->addAction("No Cursor"); |
|
228 | 228 | noCursorAction->setCheckable(true); |
|
229 | 229 | noCursorAction->setChecked( |
|
230 | 230 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::NoCursor); |
|
231 | 231 | connect(noCursorAction, &QAction::triggered, |
|
232 | 232 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); }); |
|
233 | 233 | |
|
234 | 234 | cursorMenu->addSeparator(); |
|
235 | 235 | auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor"); |
|
236 | 236 | verticalCursorAction->setCheckable(true); |
|
237 | 237 | verticalCursorAction->setChecked( |
|
238 | 238 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Vertical); |
|
239 | 239 | connect(verticalCursorAction, &QAction::triggered, |
|
240 | 240 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); }); |
|
241 | 241 | |
|
242 | 242 | auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor"); |
|
243 | 243 | temporalCursorAction->setCheckable(true); |
|
244 | 244 | temporalCursorAction->setChecked( |
|
245 | 245 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Temporal); |
|
246 | 246 | connect(temporalCursorAction, &QAction::triggered, |
|
247 | 247 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); }); |
|
248 | 248 | |
|
249 | 249 | auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor"); |
|
250 | 250 | horizontalCursorAction->setCheckable(true); |
|
251 | 251 | horizontalCursorAction->setChecked( |
|
252 | 252 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Horizontal); |
|
253 | 253 | connect(horizontalCursorAction, &QAction::triggered, |
|
254 | 254 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); }); |
|
255 | 255 | |
|
256 | 256 | auto crossCursorAction = cursorMenu->addAction("Cross Cursor"); |
|
257 | 257 | crossCursorAction->setCheckable(true); |
|
258 | 258 | crossCursorAction->setChecked( |
|
259 | 259 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Cross); |
|
260 | 260 | connect(crossCursorAction, &QAction::triggered, |
|
261 | 261 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); }); |
|
262 | 262 | |
|
263 | 263 | mainToolBar->addWidget(btnCursor); |
|
264 | 264 | |
|
265 | 265 | auto cursorModeActionGroup = new QActionGroup { this }; |
|
266 | 266 | cursorModeActionGroup->setExclusive(true); |
|
267 | 267 | cursorModeActionGroup->addAction(noCursorAction); |
|
268 | 268 | cursorModeActionGroup->addAction(verticalCursorAction); |
|
269 | 269 | cursorModeActionGroup->addAction(temporalCursorAction); |
|
270 | 270 | cursorModeActionGroup->addAction(horizontalCursorAction); |
|
271 | 271 | cursorModeActionGroup->addAction(crossCursorAction); |
|
272 | 272 | |
|
273 | 273 | // Catalog |
|
274 | 274 | mainToolBar->addSeparator(); |
|
275 | 275 | // mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues", |
|
276 | 276 | // [this]() { impl->m_CatalogExplorer->show(); }); |
|
277 | 277 | |
|
278 | 278 | // //////// // |
|
279 | 279 | // Settings // |
|
280 | 280 | // //////// // |
|
281 | 281 | |
|
282 | 282 | // Registers "general settings" widget to the settings dialog |
|
283 | 283 | impl->m_SettingsDialog->registerWidget( |
|
284 | 284 | QStringLiteral("General"), impl->m_GeneralSettingsWidget); |
|
285 | 285 | |
|
286 | 286 | // /////////// // |
|
287 | 287 | // Connections // |
|
288 | 288 | // /////////// // |
|
289 | 289 | |
|
290 | 290 | // Controllers / controllers connections |
|
291 | 291 | // connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), |
|
292 | 292 | // &sqpApp->variableController(), |
|
293 | 293 | // SLOT(onDateTimeOnSelection(DateTimeRange))); |
|
294 | 294 | |
|
295 | 295 | // Widgets / controllers connections |
|
296 | 296 | |
|
297 | 297 | // DataSource |
|
298 | 298 | connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem*)), |
|
299 | 299 | m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem*))); |
|
300 | 300 | |
|
301 | 301 | // Time |
|
302 | 302 | connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(), |
|
303 | 303 | SLOT(onTimeToUpdate(DateTimeRange))); |
|
304 | 304 | |
|
305 | 305 | // Visualization |
|
306 | 306 | connect(&sqpApp->visualizationController(), |
|
307 | SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view, | |
|
308 | SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>))); | |
|
307 | SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable2>)), m_Ui->view, | |
|
308 | SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable2>))); | |
|
309 | 309 | |
|
310 | 310 | connect(&sqpApp->visualizationController(), |
|
311 | SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange&)), m_Ui->view, | |
|
312 | SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange&))); | |
|
311 | SIGNAL(rangeChanged(std::shared_ptr<Variable2>, const DateTimeRange&)), m_Ui->view, | |
|
312 | SLOT(onRangeChanged(std::shared_ptr<Variable2>, const DateTimeRange&))); | |
|
313 | 313 | |
|
314 | 314 | // Widgets / widgets connections |
|
315 | 315 | |
|
316 | 316 | // For the following connections, we use DirectConnection to allow each widget that can |
|
317 | 317 | // potentially attach a menu to the variable's menu to do so before this menu is displayed. |
|
318 | 318 | // The order of connections is also important, since it determines the order in which each |
|
319 | 319 | // widget will attach its menu |
|
320 | 320 | connect(m_Ui->variableInspectorWidget, |
|
321 | 321 | SIGNAL(tableMenuAboutToBeDisplayed(QMenu*, const QVector<std::shared_ptr<Variable>>&)), |
|
322 | 322 | m_Ui->view, SLOT(attachVariableMenu(QMenu*, const QVector<std::shared_ptr<Variable>>&)), |
|
323 | 323 | Qt::DirectConnection); |
|
324 | 324 | } |
|
325 | 325 | |
|
326 | 326 | MainWindow::~MainWindow() {} |
|
327 | 327 | |
|
328 | 328 | void MainWindow::changeEvent(QEvent* e) |
|
329 | 329 | { |
|
330 | 330 | QMainWindow::changeEvent(e); |
|
331 | 331 | switch (e->type()) |
|
332 | 332 | { |
|
333 | 333 | case QEvent::LanguageChange: |
|
334 | 334 | m_Ui->retranslateUi(this); |
|
335 | 335 | break; |
|
336 | 336 | default: |
|
337 | 337 | break; |
|
338 | 338 | } |
|
339 | 339 | } |
|
340 | 340 | |
|
341 | 341 | void MainWindow::closeEvent(QCloseEvent* event) |
|
342 | 342 | { |
|
343 | 343 | if (!impl->checkDataToSave(this)) |
|
344 | 344 | { |
|
345 | 345 | event->ignore(); |
|
346 | 346 | } |
|
347 | 347 | else |
|
348 | 348 | { |
|
349 | 349 | event->accept(); |
|
350 | 350 | } |
|
351 | 351 | } |
|
352 | 352 | |
|
353 | 353 | void MainWindow::keyPressEvent(QKeyEvent* event) |
|
354 | 354 | { |
|
355 | 355 | switch (event->key()) |
|
356 | 356 | { |
|
357 | 357 | case Qt::Key_F11: |
|
358 | 358 | if (this->isFullScreen()) |
|
359 | 359 | { |
|
360 | 360 | this->showNormal(); |
|
361 | 361 | } |
|
362 | 362 | else |
|
363 | 363 | { |
|
364 | 364 | this->showFullScreen(); |
|
365 | 365 | } |
|
366 | 366 | break; |
|
367 | 367 | default: |
|
368 | 368 | break; |
|
369 | 369 | } |
|
370 | 370 | } |
|
371 | 371 | |
|
372 | 372 | bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget* parentWidget) |
|
373 | 373 | { |
|
374 | 374 | // auto hasChanges = sqpApp->catalogueController().hasChanges(); |
|
375 | 375 | // if (hasChanges) |
|
376 | 376 | // { |
|
377 | 377 | // // There are some unsaved changes |
|
378 | 378 | // switch (QMessageBox::question(parentWidget, tr("Save changes"), |
|
379 | 379 | // tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"), |
|
380 | 380 | // QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel, |
|
381 | 381 | // QMessageBox::SaveAll)) |
|
382 | 382 | // { |
|
383 | 383 | // case QMessageBox::SaveAll: |
|
384 | 384 | // sqpApp->catalogueController().saveAll(); |
|
385 | 385 | // break; |
|
386 | 386 | // case QMessageBox::Discard: |
|
387 | 387 | // break; |
|
388 | 388 | // case QMessageBox::Cancel: |
|
389 | 389 | // default: |
|
390 | 390 | // return false; |
|
391 | 391 | // } |
|
392 | 392 | // } |
|
393 | 393 | |
|
394 | 394 | return true; |
|
395 | 395 | } |
@@ -1,1 +1,1 | |||
|
1 | Subproject commit cc26524fb5d10feca3820e6921c9cd3cfb1a3591 | |
|
1 | Subproject commit 00ce7df31d3e11df8a418988c601247f6dc64d13 |
@@ -1,90 +1,90 | |||
|
1 | 1 | #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H |
|
2 | 2 | #define SCIQLOP_VISUALIZATIONTABWIDGET_H |
|
3 | 3 | |
|
4 | 4 | #include "Visualization/IVisualizationWidget.h" |
|
5 | 5 | |
|
6 | 6 | #include <Common/spimpl.h> |
|
7 | 7 | |
|
8 | 8 | #include <QLoggingCategory> |
|
9 | 9 | #include <QMimeData> |
|
10 | 10 | #include <QWidget> |
|
11 | 11 | |
|
12 | 12 | Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget) |
|
13 | 13 | |
|
14 | class Variable; | |
|
14 | class Variable2; | |
|
15 | 15 | class VisualizationZoneWidget; |
|
16 | 16 | |
|
17 | 17 | namespace Ui |
|
18 | 18 | { |
|
19 | 19 | class VisualizationTabWidget; |
|
20 | 20 | } // namespace Ui |
|
21 | 21 | |
|
22 | 22 | class VisualizationTabWidget : public QWidget, public IVisualizationWidget |
|
23 | 23 | { |
|
24 | 24 | Q_OBJECT |
|
25 | 25 | |
|
26 | 26 | public: |
|
27 | 27 | explicit VisualizationTabWidget(const QString& name = {}, QWidget* parent = 0); |
|
28 | 28 | virtual ~VisualizationTabWidget(); |
|
29 | 29 | |
|
30 | 30 | /// Adds a zone widget |
|
31 | 31 | void addZone(VisualizationZoneWidget* zoneWidget); |
|
32 | 32 | |
|
33 | 33 | /// Inserts a zone widget at the specified position |
|
34 | 34 | void insertZone(int index, VisualizationZoneWidget* zoneWidget); |
|
35 | 35 | |
|
36 | 36 | /// Returns the list of zone widget names in the order they are displayed |
|
37 | 37 | QStringList availableZoneWidgets() const; |
|
38 | 38 | |
|
39 | 39 | /// Returns the zone with the specified name. |
|
40 | 40 | /// If multiple zone with the same name exist, the first one is returned. |
|
41 | 41 | VisualizationZoneWidget* getZoneWithName(const QString& zoneName); |
|
42 | 42 | |
|
43 | 43 | /** |
|
44 | 44 | * Creates a zone using a variable. The variable will be displayed in a new graph of the new |
|
45 | 45 | * zone. The zone is added at the end. |
|
46 | 46 | * @param variable the variable for which to create the zone |
|
47 | 47 | * @return the pointer to the created zone |
|
48 | 48 | */ |
|
49 | 49 | VisualizationZoneWidget* createZone(std::shared_ptr<Variable2> variable); |
|
50 | 50 | |
|
51 | 51 | /** |
|
52 | 52 | * Creates a zone using a list of variables. The variables will be displayed in a new graph of |
|
53 | 53 | * the new zone. The zone is inserted at the specified index. |
|
54 | 54 | * @param variables the variables for which to create the zone |
|
55 | 55 | * @param index The index where the zone should be inserted in the layout |
|
56 | 56 | * @return the pointer to the created zone |
|
57 | 57 | */ |
|
58 | 58 | VisualizationZoneWidget* createZone( |
|
59 | 59 | const std::vector<std::shared_ptr<Variable2>>& variables, int index); |
|
60 | 60 | |
|
61 | 61 | /** |
|
62 | 62 | * Creates a zone which is empty (no variables). The zone is inserted at the specified index. |
|
63 | 63 | * @param index The index where the zone should be inserted in the layout |
|
64 | 64 | * @return the pointer to the created zone |
|
65 | 65 | */ |
|
66 | 66 | VisualizationZoneWidget* createEmptyZone(int index); |
|
67 | 67 | |
|
68 | 68 | // IVisualizationWidget interface |
|
69 | 69 | void accept(IVisualizationWidgetVisitor* visitor) override; |
|
70 | 70 | bool canDrop(Variable2& variable) const override; |
|
71 | 71 | bool contains(Variable2& variable) const override; |
|
72 | 72 | QString name() const override; |
|
73 | 73 | |
|
74 | 74 | protected: |
|
75 | 75 | void closeEvent(QCloseEvent* event) override; |
|
76 | 76 | |
|
77 | 77 | private: |
|
78 | 78 | /// @return the layout of tab in which zones are added |
|
79 | 79 | QLayout& tabLayout() const noexcept; |
|
80 | 80 | |
|
81 | 81 | Ui::VisualizationTabWidget* ui; |
|
82 | 82 | |
|
83 | 83 | class VisualizationTabWidgetPrivate; |
|
84 | 84 | spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl; |
|
85 | 85 | |
|
86 | 86 | private slots: |
|
87 | 87 | void dropMimeData(int index, const QMimeData* mimeData); |
|
88 | 88 | }; |
|
89 | 89 | |
|
90 | 90 | #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H |
@@ -1,442 +1,445 | |||
|
1 | 1 | #include "Visualization/VisualizationGraphHelper.h" |
|
2 | 2 | #include "Visualization/qcustomplot.h" |
|
3 | 3 | |
|
4 | 4 | #include <Data/ScalarTimeSerie.h> |
|
5 | 5 | #include <Data/SpectrogramTimeSerie.h> |
|
6 | 6 | #include <Data/VectorTimeSerie.h> |
|
7 | 7 | |
|
8 | 8 | #include <Variable/Variable2.h> |
|
9 | 9 | |
|
10 | 10 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper") |
|
11 | 11 | |
|
12 | 12 | namespace |
|
13 | 13 | { |
|
14 | 14 | |
|
15 | 15 | class SqpDataContainer : public QCPGraphDataContainer |
|
16 | 16 | { |
|
17 | 17 | public: |
|
18 | 18 | void appendGraphData(const QCPGraphData& data) { mData.append(data); } |
|
19 | 19 | }; |
|
20 | 20 | |
|
21 | 21 | /** |
|
22 | 22 | * Struct used to create plottables, depending on the type of the data series from which to create |
|
23 | 23 | * them |
|
24 | 24 | * @tparam T the data series' type |
|
25 | 25 | * @remarks Default implementation can't create plottables |
|
26 | 26 | */ |
|
27 | 27 | template <typename T, typename Enabled = void> |
|
28 | 28 | struct PlottablesCreator |
|
29 | 29 | { |
|
30 | 30 | static PlottablesMap createPlottables(QCustomPlot&) { return {}; } |
|
31 | 31 | }; |
|
32 | 32 | |
|
33 | 33 | PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs) |
|
34 | 34 | { |
|
35 | 35 | PlottablesMap result {}; |
|
36 | 36 | |
|
37 | 37 | // Creates {nbGraphs} QCPGraph to add to the plot |
|
38 | 38 | for (auto i = 0; i < nbGraphs; ++i) |
|
39 | 39 | { |
|
40 | 40 | auto graph = plot.addGraph(); |
|
41 | 41 | result.insert({ i, graph }); |
|
42 | 42 | } |
|
43 | 43 | |
|
44 | 44 | plot.replot(); |
|
45 | 45 | |
|
46 | 46 | return result; |
|
47 | 47 | } |
|
48 | 48 | |
|
49 | 49 | /** |
|
50 | 50 | * Specialization of PlottablesCreator for scalars |
|
51 | 51 | * @sa ScalarSeries |
|
52 | 52 | */ |
|
53 | 53 | template <typename T> |
|
54 | 54 | struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>> |
|
55 | 55 | { |
|
56 | 56 | static PlottablesMap createPlottables(QCustomPlot& plot) { return createGraphs(plot, 1); } |
|
57 | 57 | }; |
|
58 | 58 | |
|
59 | 59 | /** |
|
60 | 60 | * Specialization of PlottablesCreator for vectors |
|
61 | 61 | * @sa VectorSeries |
|
62 | 62 | */ |
|
63 | 63 | template <typename T> |
|
64 | 64 | struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>> |
|
65 | 65 | { |
|
66 | 66 | static PlottablesMap createPlottables(QCustomPlot& plot) { return createGraphs(plot, 3); } |
|
67 | 67 | }; |
|
68 | 68 | |
|
69 | 69 | /** |
|
70 | 70 | * Specialization of PlottablesCreator for spectrograms |
|
71 | 71 | * @sa SpectrogramSeries |
|
72 | 72 | */ |
|
73 | 73 | template <typename T> |
|
74 | 74 | struct PlottablesCreator<T, |
|
75 | 75 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> |
|
76 | 76 | { |
|
77 | 77 | static PlottablesMap createPlottables(QCustomPlot& plot) |
|
78 | 78 | { |
|
79 | 79 | PlottablesMap result {}; |
|
80 | 80 | result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } }); |
|
81 | 81 | |
|
82 | 82 | plot.replot(); |
|
83 | 83 | |
|
84 | 84 | return result; |
|
85 | 85 | } |
|
86 | 86 | }; |
|
87 | 87 | |
|
88 | 88 | /** |
|
89 | 89 | * Struct used to update plottables, depending on the type of the data series from which to update |
|
90 | 90 | * them |
|
91 | 91 | * @tparam T the data series' type |
|
92 | 92 | * @remarks Default implementation can't update plottables |
|
93 | 93 | */ |
|
94 | 94 | template <typename T, typename Enabled = void> |
|
95 | 95 | struct PlottablesUpdater |
|
96 | 96 | { |
|
97 | 97 | static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&) |
|
98 | 98 | { |
|
99 | 99 | qCCritical(LOG_VisualizationGraphHelper()) |
|
100 | 100 | << QObject::tr("Can't set plot y-axis range: unmanaged data series type"); |
|
101 | 101 | } |
|
102 | 102 | |
|
103 | 103 | static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool) |
|
104 | 104 | { |
|
105 | 105 | qCCritical(LOG_VisualizationGraphHelper()) |
|
106 | 106 | << QObject::tr("Can't update plottables: unmanaged data series type"); |
|
107 | 107 | } |
|
108 | 108 | }; |
|
109 | 109 | |
|
110 | 110 | /** |
|
111 | 111 | * Specialization of PlottablesUpdater for scalars and vectors |
|
112 | 112 | * @sa ScalarSeries |
|
113 | 113 | * @sa VectorSeries |
|
114 | 114 | */ |
|
115 | 115 | template <typename T> |
|
116 | 116 | struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>> |
|
117 | 117 | { |
|
118 | 118 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) |
|
119 | 119 | { |
|
120 | 120 | auto minValue = 0., maxValue = 0.; |
|
121 | 121 | if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries)) |
|
122 | 122 | { |
|
123 | maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v(); | |
|
124 | minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v(); | |
|
123 | if (serie->size()) | |
|
124 | { | |
|
125 | maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v(); | |
|
126 | minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v(); | |
|
127 | } | |
|
125 | 128 | } |
|
126 | 129 | plot.yAxis->setRange(QCPRange { minValue, maxValue }); |
|
127 | 130 | } |
|
128 | 131 | |
|
129 | 132 | static void updatePlottables( |
|
130 | 133 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) |
|
131 | 134 | { |
|
132 | 135 | |
|
133 | 136 | // For each plottable to update, resets its data |
|
134 | 137 | for (const auto& plottable : plottables) |
|
135 | 138 | { |
|
136 | 139 | if (auto graph = dynamic_cast<QCPGraph*>(plottable.second)) |
|
137 | 140 | { |
|
138 | 141 | auto dataContainer = QSharedPointer<SqpDataContainer>::create(); |
|
139 | 142 | if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries)) |
|
140 | 143 | { |
|
141 | 144 | std::for_each( |
|
142 | 145 | std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) { |
|
143 | 146 | dataContainer->appendGraphData(QCPGraphData(value.t(), value.v())); |
|
144 | 147 | }); |
|
145 | 148 | } |
|
146 | 149 | graph->setData(dataContainer); |
|
147 | 150 | } |
|
148 | 151 | } |
|
149 | 152 | |
|
150 | 153 | if (!plottables.empty()) |
|
151 | 154 | { |
|
152 | 155 | auto plot = plottables.begin()->second->parentPlot(); |
|
153 | 156 | |
|
154 | 157 | if (rescaleAxes) |
|
155 | 158 | { |
|
156 | 159 | plot->rescaleAxes(); |
|
157 | 160 | } |
|
158 | 161 | } |
|
159 | 162 | } |
|
160 | 163 | }; |
|
161 | 164 | |
|
162 | 165 | |
|
163 | 166 | template <typename T> |
|
164 | 167 | struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>> |
|
165 | 168 | { |
|
166 | 169 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) |
|
167 | 170 | { |
|
168 | 171 | double minValue = 0., maxValue = 0.; |
|
169 | 172 | if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries)) |
|
170 | 173 | { |
|
171 | 174 | std::for_each( |
|
172 | 175 | std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) { |
|
173 | 176 | minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z }); |
|
174 | 177 | maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z }); |
|
175 | 178 | }); |
|
176 | 179 | } |
|
177 | 180 | |
|
178 | 181 | plot.yAxis->setRange(QCPRange { minValue, maxValue }); |
|
179 | 182 | } |
|
180 | 183 | |
|
181 | 184 | static void updatePlottables( |
|
182 | 185 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) |
|
183 | 186 | { |
|
184 | 187 | |
|
185 | 188 | // For each plottable to update, resets its data |
|
186 | 189 | for (const auto& plottable : plottables) |
|
187 | 190 | { |
|
188 | 191 | if (auto graph = dynamic_cast<QCPGraph*>(plottable.second)) |
|
189 | 192 | { |
|
190 | 193 | auto dataContainer = QSharedPointer<SqpDataContainer>::create(); |
|
191 | 194 | if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries)) |
|
192 | 195 | { |
|
193 | 196 | switch (plottable.first) |
|
194 | 197 | { |
|
195 | 198 | case 0: |
|
196 | 199 | std::for_each(std::begin(*serie), std::end(*serie), |
|
197 | 200 | [&dataContainer](const auto& value) { |
|
198 | 201 | dataContainer->appendGraphData( |
|
199 | 202 | QCPGraphData(value.t(), value.v().x)); |
|
200 | 203 | }); |
|
201 | 204 | break; |
|
202 | 205 | case 1: |
|
203 | 206 | std::for_each(std::begin(*serie), std::end(*serie), |
|
204 | 207 | [&dataContainer](const auto& value) { |
|
205 | 208 | dataContainer->appendGraphData( |
|
206 | 209 | QCPGraphData(value.t(), value.v().y)); |
|
207 | 210 | }); |
|
208 | 211 | break; |
|
209 | 212 | case 2: |
|
210 | 213 | std::for_each(std::begin(*serie), std::end(*serie), |
|
211 | 214 | [&dataContainer](const auto& value) { |
|
212 | 215 | dataContainer->appendGraphData( |
|
213 | 216 | QCPGraphData(value.t(), value.v().z)); |
|
214 | 217 | }); |
|
215 | 218 | break; |
|
216 | 219 | default: |
|
217 | 220 | break; |
|
218 | 221 | } |
|
219 | 222 | } |
|
220 | 223 | graph->setData(dataContainer); |
|
221 | 224 | } |
|
222 | 225 | } |
|
223 | 226 | |
|
224 | 227 | if (!plottables.empty()) |
|
225 | 228 | { |
|
226 | 229 | auto plot = plottables.begin()->second->parentPlot(); |
|
227 | 230 | |
|
228 | 231 | if (rescaleAxes) |
|
229 | 232 | { |
|
230 | 233 | plot->rescaleAxes(); |
|
231 | 234 | } |
|
232 | 235 | } |
|
233 | 236 | } |
|
234 | 237 | }; |
|
235 | 238 | |
|
236 | 239 | /** |
|
237 | 240 | * Specialization of PlottablesUpdater for spectrograms |
|
238 | 241 | * @sa SpectrogramSeries |
|
239 | 242 | */ |
|
240 | 243 | template <typename T> |
|
241 | 244 | struct PlottablesUpdater<T, |
|
242 | 245 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> |
|
243 | 246 | { |
|
244 | 247 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) |
|
245 | 248 | { |
|
246 | 249 | // TODO |
|
247 | 250 | // double min, max; |
|
248 | 251 | // std::tie(min, max) = dataSeries.yBounds(); |
|
249 | 252 | |
|
250 | 253 | // if (!std::isnan(min) && !std::isnan(max)) |
|
251 | 254 | // { |
|
252 | 255 | // plot.yAxis->setRange(QCPRange { min, max }); |
|
253 | 256 | // } |
|
254 | 257 | } |
|
255 | 258 | |
|
256 | 259 | static void updatePlottables( |
|
257 | 260 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) |
|
258 | 261 | { |
|
259 | 262 | // TODO |
|
260 | 263 | // if (plottables.empty()) |
|
261 | 264 | // { |
|
262 | 265 | // qCDebug(LOG_VisualizationGraphHelper()) |
|
263 | 266 | // << QObject::tr("Can't update spectrogram: no colormap has been |
|
264 | 267 | // associated"); |
|
265 | 268 | // return; |
|
266 | 269 | // } |
|
267 | 270 | |
|
268 | 271 | // // Gets the colormap to update (normally there is only one colormap) |
|
269 | 272 | // Q_ASSERT(plottables.size() == 1); |
|
270 | 273 | // auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0)); |
|
271 | 274 | // Q_ASSERT(colormap != nullptr); |
|
272 | 275 | |
|
273 | 276 | // dataSeries.lockRead(); |
|
274 | 277 | |
|
275 | 278 | // // Processing spectrogram data for display in QCustomPlot |
|
276 | 279 | // auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd); |
|
277 | 280 | |
|
278 | 281 | // // Computes logarithmic y-axis resolution for the spectrogram |
|
279 | 282 | // auto yData = its.first->y(); |
|
280 | 283 | // auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true); |
|
281 | 284 | |
|
282 | 285 | // // Generates mesh for colormap |
|
283 | 286 | // auto mesh = DataSeriesUtils::regularMesh(its.first, its.second, |
|
284 | 287 | // DataSeriesUtils::Resolution { dataSeries.xResolution() }, yResolution); |
|
285 | 288 | |
|
286 | 289 | // dataSeries.unlock(); |
|
287 | 290 | |
|
288 | 291 | // colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY); |
|
289 | 292 | // if (!mesh.isEmpty()) |
|
290 | 293 | // { |
|
291 | 294 | // colormap->data()->setRange(QCPRange { mesh.m_XMin, mesh.xMax() }, |
|
292 | 295 | // // y-axis range is converted to linear values |
|
293 | 296 | // QCPRange { std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax()) }); |
|
294 | 297 | |
|
295 | 298 | // // Sets values |
|
296 | 299 | // auto index = 0; |
|
297 | 300 | // for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, |
|
298 | 301 | // ++index) |
|
299 | 302 | // { |
|
300 | 303 | // auto xIndex = index % mesh.m_NbX; |
|
301 | 304 | // auto yIndex = index / mesh.m_NbX; |
|
302 | 305 | |
|
303 | 306 | // colormap->data()->setCell(xIndex, yIndex, *it); |
|
304 | 307 | |
|
305 | 308 | // // Makes the NaN values to be transparent in the colormap |
|
306 | 309 | // if (std::isnan(*it)) |
|
307 | 310 | // { |
|
308 | 311 | // colormap->data()->setAlpha(xIndex, yIndex, 0); |
|
309 | 312 | // } |
|
310 | 313 | // } |
|
311 | 314 | // } |
|
312 | 315 | |
|
313 | 316 | // // Rescales axes |
|
314 | 317 | // auto plot = colormap->parentPlot(); |
|
315 | 318 | |
|
316 | 319 | // if (rescaleAxes) |
|
317 | 320 | // { |
|
318 | 321 | // plot->rescaleAxes(); |
|
319 | 322 | // } |
|
320 | 323 | } |
|
321 | 324 | }; |
|
322 | 325 | |
|
323 | 326 | /** |
|
324 | 327 | * Helper used to create/update plottables |
|
325 | 328 | */ |
|
326 | 329 | struct IPlottablesHelper |
|
327 | 330 | { |
|
328 | 331 | virtual ~IPlottablesHelper() noexcept = default; |
|
329 | 332 | virtual PlottablesMap create(QCustomPlot& plot) const = 0; |
|
330 | 333 | virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0; |
|
331 | 334 | virtual void update( |
|
332 | 335 | PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0; |
|
333 | 336 | }; |
|
334 | 337 | |
|
335 | 338 | /** |
|
336 | 339 | * Default implementation of IPlottablesHelper, which takes data series to create/update plottables |
|
337 | 340 | * @tparam T the data series' type |
|
338 | 341 | */ |
|
339 | 342 | template <typename T> |
|
340 | 343 | struct PlottablesHelper : public IPlottablesHelper |
|
341 | 344 | { |
|
342 | 345 | explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {} |
|
343 | 346 | |
|
344 | 347 | PlottablesMap create(QCustomPlot& plot) const override |
|
345 | 348 | { |
|
346 | 349 | return PlottablesCreator<T>::createPlottables(plot); |
|
347 | 350 | } |
|
348 | 351 | |
|
349 | 352 | void update( |
|
350 | 353 | PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override |
|
351 | 354 | { |
|
352 | 355 | if (m_DataSeries) |
|
353 | 356 | { |
|
354 | 357 | PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes); |
|
355 | 358 | } |
|
356 | 359 | else |
|
357 | 360 | { |
|
358 | 361 | qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency " |
|
359 | 362 | "between the type of data series and the " |
|
360 | 363 | "type supposed"; |
|
361 | 364 | } |
|
362 | 365 | } |
|
363 | 366 | |
|
364 | 367 | void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override |
|
365 | 368 | { |
|
366 | 369 | if (m_DataSeries) |
|
367 | 370 | { |
|
368 | 371 | PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot); |
|
369 | 372 | } |
|
370 | 373 | else |
|
371 | 374 | { |
|
372 | 375 | qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency " |
|
373 | 376 | "between the type of data series and the " |
|
374 | 377 | "type supposed"; |
|
375 | 378 | } |
|
376 | 379 | } |
|
377 | 380 | |
|
378 | 381 | std::shared_ptr<T> m_DataSeries; |
|
379 | 382 | }; |
|
380 | 383 | |
|
381 | 384 | /// Creates IPlottablesHelper according to the type of data series a variable holds |
|
382 | 385 | std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept |
|
383 | 386 | { |
|
384 | 387 | switch (variable->type()) |
|
385 | 388 | { |
|
386 | 389 | case DataSeriesType::SCALAR: |
|
387 | 390 | return std::make_unique<PlottablesHelper<ScalarTimeSerie>>( |
|
388 | 391 | std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data())); |
|
389 | 392 | case DataSeriesType::SPECTROGRAM: |
|
390 | 393 | return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>( |
|
391 | 394 | std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data())); |
|
392 | 395 | case DataSeriesType::VECTOR: |
|
393 | 396 | return std::make_unique<PlottablesHelper<VectorTimeSerie>>( |
|
394 | 397 | std::dynamic_pointer_cast<VectorTimeSerie>(variable->data())); |
|
395 | 398 | default: |
|
396 | 399 | // Creates default helper |
|
397 | 400 | break; |
|
398 | 401 | } |
|
399 | 402 | |
|
400 | 403 | return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr); |
|
401 | 404 | } |
|
402 | 405 | |
|
403 | 406 | } // namespace |
|
404 | 407 | |
|
405 | 408 | PlottablesMap VisualizationGraphHelper::create( |
|
406 | 409 | std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept |
|
407 | 410 | { |
|
408 | 411 | if (variable) |
|
409 | 412 | { |
|
410 | 413 | auto helper = createHelper(variable); |
|
411 | 414 | auto plottables = helper->create(plot); |
|
412 | 415 | return plottables; |
|
413 | 416 | } |
|
414 | 417 | else |
|
415 | 418 | { |
|
416 | 419 | qCDebug(LOG_VisualizationGraphHelper()) |
|
417 | 420 | << QObject::tr("Can't create graph plottables : the variable is null"); |
|
418 | 421 | return PlottablesMap {}; |
|
419 | 422 | } |
|
420 | 423 | } |
|
421 | 424 | |
|
422 | 425 | void VisualizationGraphHelper::setYAxisRange( |
|
423 | 426 | std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept |
|
424 | 427 | { |
|
425 | 428 | if (variable) |
|
426 | 429 | { |
|
427 | 430 | auto helper = createHelper(variable); |
|
428 | 431 | helper->setYAxisRange(variable->range(), plot); |
|
429 | 432 | } |
|
430 | 433 | else |
|
431 | 434 | { |
|
432 | 435 | qCDebug(LOG_VisualizationGraphHelper()) |
|
433 | 436 | << QObject::tr("Can't set y-axis range of plot: the variable is null"); |
|
434 | 437 | } |
|
435 | 438 | } |
|
436 | 439 | |
|
437 | 440 | void VisualizationGraphHelper::updateData( |
|
438 | 441 | PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime) |
|
439 | 442 | { |
|
440 | 443 | auto helper = createHelper(variable); |
|
441 | 444 | helper->update(plottables, dateTime); |
|
442 | 445 | } |
@@ -1,3 +1,4 | |||
|
1 | 1 | add_subdirectory(mockplugin) |
|
2 |
add_subdirectory( |
|
|
3 |
add_subdirectory( |
|
|
2 | add_subdirectory(python_providers) | |
|
3 | #add_subdirectory(amda) | |
|
4 | #add_subdirectory(generic_ws) |
@@ -1,30 +1,30 | |||
|
1 | 1 | #ifndef SCIQLOP_AMDAPROVIDER_H |
|
2 | 2 | #define SCIQLOP_AMDAPROVIDER_H |
|
3 | 3 | |
|
4 | 4 | #include "AmdaGlobal.h" |
|
5 | 5 | |
|
6 | 6 | #include <Data/IDataProvider.h> |
|
7 | 7 | |
|
8 | 8 | #include <QLoggingCategory> |
|
9 | 9 | |
|
10 | 10 | #include <map> |
|
11 | 11 | |
|
12 | 12 | Q_DECLARE_LOGGING_CATEGORY(LOG_AmdaProvider) |
|
13 | 13 | |
|
14 | 14 | class QNetworkReply; |
|
15 | 15 | class QNetworkRequest; |
|
16 | 16 | |
|
17 | 17 | /** |
|
18 | 18 | * @brief The AmdaProvider class is an example of how a data provider can generate data |
|
19 | 19 | */ |
|
20 |
class SCIQLOP_AMDA_EXPORT AmdaProvider : public IDataProvider |
|
|
20 | class SCIQLOP_AMDA_EXPORT AmdaProvider : public IDataProvider | |
|
21 | { | |
|
21 | 22 | Q_OBJECT |
|
22 | 23 | public: |
|
23 | 24 | explicit AmdaProvider(); |
|
24 | 25 | std::shared_ptr<IDataProvider> clone() const override; |
|
25 | 26 | |
|
26 |
virtual |
|
|
27 | ||
|
27 | virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters) override; | |
|
28 | 28 | }; |
|
29 | 29 | |
|
30 | 30 | #endif // SCIQLOP_AMDAPROVIDER_H |
@@ -1,88 +1,85 | |||
|
1 | 1 | #include "AmdaProvider.h" |
|
2 | 2 | #include "AmdaDefs.h" |
|
3 | 3 | #include "AmdaResultParser.h" |
|
4 | 4 | #include "AmdaServer.h" |
|
5 | 5 | |
|
6 | 6 | #include <Common/DateUtils.h> |
|
7 | 7 | #include <Data/DataProviderParameters.h> |
|
8 | 8 | #include <Network/NetworkController.h> |
|
9 | 9 | #include <SqpApplication.h> |
|
10 | #include <Variable/Variable.h> | |
|
11 | 10 | |
|
11 | #include <Network/Downloader.h> | |
|
12 | #include <QJsonDocument> | |
|
12 | 13 | #include <QNetworkAccessManager> |
|
13 | 14 | #include <QNetworkReply> |
|
14 | 15 | #include <QTemporaryFile> |
|
15 | 16 | #include <QThread> |
|
16 | #include <QJsonDocument> | |
|
17 | #include <Network/Downloader.h> | |
|
18 | 17 | |
|
19 | 18 | Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider") |
|
20 | 19 | |
|
21 |
namespace |
|
|
20 | namespace | |
|
21 | { | |
|
22 | 22 | |
|
23 | 23 | /// URL format for a request on AMDA server. The parameters are as follows: |
|
24 | 24 | /// - %1: server URL |
|
25 | 25 | /// - %2: start date |
|
26 | 26 | /// - %3: end date |
|
27 | 27 | /// - %4: parameter id |
|
28 | 28 | /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/ |
|
29 | 29 | const auto AMDA_URL_FORMAT = QStringLiteral( |
|
30 | 30 | "http://%1/php/rest/" |
|
31 | 31 | "getParameter.php?startTime=%2&stopTime=%3¶meterID=%4&outputFormat=ASCII&" |
|
32 | 32 | "timeFormat=ISO8601&gzip=0"); |
|
33 | 33 | |
|
34 | 34 | const auto AMDA_URL_FORMAT_WITH_TOKEN = QStringLiteral( |
|
35 | 35 | "http://%1/php/rest/" |
|
36 | 36 | "getParameter.php?startTime=%2&stopTime=%3¶meterID=%4&outputFormat=ASCII&" |
|
37 | 37 | "timeFormat=ISO8601&gzip=0&" |
|
38 | 38 | "token=%5"); |
|
39 | 39 | |
|
40 | 40 | const auto AMDA_TOKEN_URL_FORMAT = QStringLiteral( |
|
41 | 41 | "http://%1/php/rest/" |
|
42 | 42 | "auth.php"); |
|
43 | 43 | |
|
44 | 44 | /// Dates format passed in the URL (e.g 2013-09-23T09:00) |
|
45 | 45 | const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss"); |
|
46 | 46 | |
|
47 | 47 | /// Formats a time to a date that can be passed in URL |
|
48 | 48 | QString dateFormat(double sqpRange) noexcept |
|
49 | 49 | { |
|
50 | 50 | auto dateTime = DateUtils::dateTime(sqpRange); |
|
51 | 51 | return dateTime.toString(AMDA_TIME_FORMAT); |
|
52 | 52 | } |
|
53 | 53 | |
|
54 | 54 | |
|
55 | 55 | } // namespace |
|
56 | 56 | |
|
57 | AmdaProvider::AmdaProvider() | |
|
58 | { | |
|
59 | ||
|
60 | } | |
|
57 | AmdaProvider::AmdaProvider() {} | |
|
61 | 58 | |
|
62 | 59 | std::shared_ptr<IDataProvider> AmdaProvider::clone() const |
|
63 | 60 | { |
|
64 | 61 | // No copy is made in the clone |
|
65 | 62 | return std::make_shared<AmdaProvider>(); |
|
66 | 63 | } |
|
67 | 64 | |
|
68 |
|
|
|
65 | TimeSeries::ITimeSerie* AmdaProvider::getData(const DataProviderParameters& parameters) | |
|
69 | 66 | { |
|
70 | 67 | auto range = parameters.m_Range; |
|
71 | 68 | auto metaData = parameters.m_Data; |
|
72 | 69 | auto productId = metaData.value(AMDA_XML_ID_KEY).toString(); |
|
73 | 70 | auto productValueType |
|
74 | 71 | = DataSeriesTypeUtils::fromString(metaData.value(AMDA_DATA_TYPE_KEY).toString()); |
|
75 | 72 | auto startDate = dateFormat(range.m_TStart); |
|
76 | 73 | auto endDate = dateFormat(range.m_TEnd); |
|
77 | QVariantHash urlProperties{{AMDA_SERVER_KEY, metaData.value(AMDA_SERVER_KEY)}}; | |
|
78 | auto token_url = QString{AMDA_TOKEN_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties)); | |
|
74 | QVariantHash urlProperties { { AMDA_SERVER_KEY, metaData.value(AMDA_SERVER_KEY) } }; | |
|
75 | auto token_url | |
|
76 | = QString { AMDA_TOKEN_URL_FORMAT }.arg(AmdaServer::instance().url(urlProperties)); | |
|
79 | 77 | auto response = Downloader::get(token_url); |
|
80 | auto url = QString{AMDA_URL_FORMAT_WITH_TOKEN}.arg(AmdaServer::instance().url(urlProperties), | |
|
81 |
|
|
|
78 | auto url = QString { AMDA_URL_FORMAT_WITH_TOKEN }.arg(AmdaServer::instance().url(urlProperties), | |
|
79 | startDate, endDate, productId, QString(response.data())); | |
|
82 | 80 | response = Downloader::get(url); |
|
83 | 81 | auto test = QJsonDocument::fromJson(response.data()); |
|
84 | 82 | url = test["dataFileURLs"].toString(); |
|
85 | 83 | response = Downloader::get(url); |
|
86 |
return |
|
|
84 | return nullptr; // AmdaResultParser::readTxt(QTextStream { response.data() }, productValueType); | |
|
87 | 85 | } |
|
88 |
@@ -1,150 +1,149 | |||
|
1 | 1 | #include "AmdaResultParser.h" |
|
2 | 2 | |
|
3 | 3 | #include "AmdaResultParserHelper.h" |
|
4 | 4 | |
|
5 | 5 | #include <QFile> |
|
6 | 6 | |
|
7 | #include <Data/IDataSeries.h> | |
|
8 | 7 | #include <cmath> |
|
9 | 8 | |
|
10 | 9 | Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser") |
|
11 | 10 | |
|
12 | 11 | namespace |
|
13 | 12 | { |
|
14 | 13 | |
|
15 | 14 | /// Message in result file when the file was not found on server |
|
16 | 15 | const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found"); |
|
17 | 16 | |
|
18 | 17 | /// Checks if a line is a comment line |
|
19 | 18 | bool isCommentLine(const QString& line) |
|
20 | 19 | { |
|
21 | 20 | return line.startsWith("#"); |
|
22 | 21 | } |
|
23 | 22 | |
|
24 | 23 | /** |
|
25 | 24 | * Creates helper that will be used to read AMDA file, according to the type passed as parameter |
|
26 | 25 | * @param valueType the type of values expected in the AMDA file (scalars, vectors, spectrograms...) |
|
27 | 26 | * @return the helper created |
|
28 | 27 | */ |
|
29 | 28 | std::unique_ptr<IAmdaResultParserHelper> createHelper(DataSeriesType valueType) |
|
30 | 29 | { |
|
31 | 30 | switch (valueType) |
|
32 | 31 | { |
|
33 | 32 | case DataSeriesType::SCALAR: |
|
34 | 33 | return std::make_unique<ScalarParserHelper>(); |
|
35 | 34 | case DataSeriesType::SPECTROGRAM: |
|
36 | 35 | return std::make_unique<SpectrogramParserHelper>(); |
|
37 | 36 | case DataSeriesType::VECTOR: |
|
38 | 37 | return std::make_unique<VectorParserHelper>(); |
|
39 | 38 | case DataSeriesType::NONE: |
|
40 | 39 | // Invalid case |
|
41 | 40 | break; |
|
42 | 41 | } |
|
43 | 42 | |
|
44 | 43 | // Invalid cases |
|
45 | 44 | qCCritical(LOG_AmdaResultParser()) |
|
46 | 45 | << QObject::tr("Can't create helper to read result file: unsupported type"); |
|
47 | 46 | return nullptr; |
|
48 | 47 | } |
|
49 | 48 | |
|
50 | 49 | /** |
|
51 | 50 | * Reads properties of the stream passed as parameter |
|
52 | 51 | * @param helper the helper used to read properties line by line |
|
53 | 52 | * @param stream the stream to read |
|
54 | 53 | */ |
|
55 | 54 | void readProperties(IAmdaResultParserHelper& helper, QTextStream& stream) |
|
56 | 55 | { |
|
57 | 56 | // Searches properties in the comment lines (as long as the reading has not reached the data) |
|
58 | 57 | // AMDA V2: while (stream.readLineInto(&line) && !line.contains(DATA_HEADER_REGEX)) { |
|
59 | 58 | QString line {}; |
|
60 | 59 | while (stream.readLineInto(&line) && isCommentLine(line)) |
|
61 | 60 | { |
|
62 | 61 | helper.readPropertyLine(line); |
|
63 | 62 | } |
|
64 | 63 | } |
|
65 | 64 | |
|
66 | 65 | /** |
|
67 | 66 | * Reads results of the stream passed as parameter |
|
68 | 67 | * @param helper the helper used to read results line by line |
|
69 | 68 | * @param stream the stream to read |
|
70 | 69 | */ |
|
71 | 70 | void readResults(IAmdaResultParserHelper& helper, QTextStream& stream) |
|
72 | 71 | { |
|
73 | 72 | QString line {}; |
|
74 | 73 | |
|
75 | 74 | // Skip comment lines |
|
76 | 75 | while (stream.readLineInto(&line) && isCommentLine(line)) |
|
77 | 76 | { |
|
78 | 77 | } |
|
79 | 78 | |
|
80 | 79 | if (!stream.atEnd()) |
|
81 | 80 | { |
|
82 | 81 | do |
|
83 | 82 | { |
|
84 | 83 | helper.readResultLine(line); |
|
85 | 84 | } while (stream.readLineInto(&line)); |
|
86 | 85 | } |
|
87 | 86 | } |
|
88 | 87 | |
|
89 | 88 | } // namespace |
|
90 | 89 | |
|
91 | 90 | std::shared_ptr<IDataSeries> AmdaResultParser::readTxt( |
|
92 | 91 | const QString& filePath, DataSeriesType type) noexcept |
|
93 | 92 | { |
|
94 | 93 | if (type == DataSeriesType::NONE) |
|
95 | 94 | { |
|
96 | 95 | qCCritical(LOG_AmdaResultParser()) |
|
97 | 96 | << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown"); |
|
98 | 97 | return nullptr; |
|
99 | 98 | } |
|
100 | 99 | |
|
101 | 100 | QFile file { filePath }; |
|
102 | 101 | |
|
103 | 102 | if (!file.open(QFile::ReadOnly | QIODevice::Text)) |
|
104 | 103 | { |
|
105 | 104 | qCCritical(LOG_AmdaResultParser()) |
|
106 | 105 | << QObject::tr("Can't retrieve AMDA data from file %1: %2") |
|
107 | 106 | .arg(filePath, file.errorString()); |
|
108 | 107 | return nullptr; |
|
109 | 108 | } |
|
110 | 109 | |
|
111 | 110 | return std::shared_ptr<IDataSeries> { AmdaResultParser::readTxt(QTextStream { &file }, type) }; |
|
112 | 111 | } |
|
113 | 112 | |
|
114 | 113 | IDataSeries* AmdaResultParser::readTxt(QTextStream stream, DataSeriesType type) noexcept |
|
115 | 114 | { |
|
116 | 115 | if (type == DataSeriesType::NONE) |
|
117 | 116 | { |
|
118 | 117 | return nullptr; |
|
119 | 118 | } |
|
120 | 119 | |
|
121 | 120 | // Checks if the file was found on the server |
|
122 | 121 | auto firstLine = stream.readLine(); |
|
123 | 122 | if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) |
|
124 | 123 | { |
|
125 | 124 | return nullptr; |
|
126 | 125 | } |
|
127 | 126 | |
|
128 | 127 | auto helper = createHelper(type); |
|
129 | 128 | Q_ASSERT(helper != nullptr); |
|
130 | 129 | |
|
131 | 130 | // Reads header file to retrieve properties |
|
132 | 131 | stream.seek(0); // returns to the beginning of the file |
|
133 | 132 | readProperties(*helper, stream); |
|
134 | 133 | |
|
135 | 134 | // Checks properties |
|
136 | 135 | if (helper->checkProperties()) |
|
137 | 136 | { |
|
138 | 137 | // Reads results |
|
139 | 138 | // AMDA V2: remove line |
|
140 | 139 | stream.seek(0); // returns to the beginning of the file |
|
141 | 140 | readResults(*helper, stream); |
|
142 | 141 | |
|
143 | 142 | // Creates data series |
|
144 | 143 | return helper->createSeries(); |
|
145 | 144 | } |
|
146 | 145 | else |
|
147 | 146 | { |
|
148 | 147 | return nullptr; |
|
149 | 148 | } |
|
150 | 149 | } |
@@ -1,128 +1,131 | |||
|
1 | 1 | #ifndef SCIQLOP_FUZZINGDEFS_H |
|
2 | 2 | #define SCIQLOP_FUZZINGDEFS_H |
|
3 | 3 | |
|
4 | 4 | #include <Data/DateTimeRange.h> |
|
5 | 5 | |
|
6 | 6 | #include <QString> |
|
7 | 7 | #include <QUuid> |
|
8 | 8 | #include <QVariantHash> |
|
9 | 9 | |
|
10 | 10 | #include <memory> |
|
11 | 11 | #include <set> |
|
12 | 12 | |
|
13 | 13 | // /////// // |
|
14 | 14 | // Aliases // |
|
15 | 15 | // /////// // |
|
16 | 16 | |
|
17 | 17 | using MetadataPool = std::vector<QVariantHash>; |
|
18 | 18 | Q_DECLARE_METATYPE(MetadataPool) |
|
19 | 19 | |
|
20 | 20 | using Properties = QVariantHash; |
|
21 | 21 | |
|
22 | 22 | // ///////// // |
|
23 | 23 | // Constants // |
|
24 | 24 | // ///////// // |
|
25 | 25 | |
|
26 | 26 | /// Timeout set for data acquisition for an operation (in ms) |
|
27 | 27 | extern const QString ACQUISITION_TIMEOUT_PROPERTY; |
|
28 | 28 | |
|
29 | 29 | /// Max number of operations to generate |
|
30 | 30 | extern const QString NB_MAX_OPERATIONS_PROPERTY; |
|
31 | 31 | |
|
32 | 32 | /// Max number of sync groups to create through operations |
|
33 | 33 | extern const QString NB_MAX_SYNC_GROUPS_PROPERTY; |
|
34 | 34 | |
|
35 | 35 | /// Max number of variables to manipulate through operations |
|
36 | 36 | extern const QString NB_MAX_VARIABLES_PROPERTY; |
|
37 | 37 | |
|
38 | 38 | /// Set of operations available for the test |
|
39 | 39 | extern const QString AVAILABLE_OPERATIONS_PROPERTY; |
|
40 | 40 | |
|
41 | 41 | /// Tolerance used for variable's cache (in ratio) |
|
42 | 42 | extern const QString CACHE_TOLERANCE_PROPERTY; |
|
43 | 43 | |
|
44 | 44 | /// Range with which the timecontroller is initialized |
|
45 | 45 | extern const QString INITIAL_RANGE_PROPERTY; |
|
46 | 46 | |
|
47 | 47 | /// Max range that an operation can reach |
|
48 | 48 | extern const QString MAX_RANGE_PROPERTY; |
|
49 | 49 | |
|
50 | 50 | /// Set of metadata that can be associated to a variable |
|
51 | 51 | extern const QString METADATA_POOL_PROPERTY; |
|
52 | 52 | |
|
53 | 53 | /// Provider used to retrieve data |
|
54 | 54 | extern const QString PROVIDER_PROPERTY; |
|
55 | 55 | |
|
56 | 56 | /// Min/max times left for an operation to execute |
|
57 | 57 | extern const QString OPERATION_DELAY_BOUNDS_PROPERTY; |
|
58 | 58 | |
|
59 | 59 | /// Validators used to validate an operation |
|
60 | 60 | extern const QString VALIDATORS_PROPERTY; |
|
61 | 61 | |
|
62 | 62 | /// Min/max number of operations to execute before calling validation of the current test's state |
|
63 | 63 | extern const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY; |
|
64 | 64 | |
|
65 | 65 | // /////// // |
|
66 | 66 | // Structs // |
|
67 | 67 | // /////// // |
|
68 | 68 | |
|
69 | 69 | class Variable; |
|
70 |
struct VariableState |
|
|
71 | std::shared_ptr<Variable> m_Variable{nullptr}; | |
|
72 | DateTimeRange m_Range{INVALID_RANGE}; | |
|
70 | struct VariableState | |
|
71 | { | |
|
72 | std::shared_ptr<Variable> m_Variable { nullptr }; | |
|
73 | DateTimeRange m_Range { INVALID_RANGE }; | |
|
73 | 74 | }; |
|
74 | 75 | |
|
75 | 76 | using VariableId = int; |
|
76 | 77 | using VariablesPool = std::map<VariableId, VariableState>; |
|
77 | 78 | |
|
78 | 79 | /** |
|
79 | 80 | * Defines a synchronization group for a fuzzing state. A group reports the variables synchronized |
|
80 | 81 | * with each other, and the current range of the group (i.e. range of the last synchronized variable |
|
81 | 82 | * that has been moved) |
|
82 | 83 | */ |
|
83 |
struct SyncGroup |
|
|
84 | std::set<VariableId> m_Variables{}; | |
|
85 | DateTimeRange m_Range{INVALID_RANGE}; | |
|
84 | struct SyncGroup | |
|
85 | { | |
|
86 | std::set<VariableId> m_Variables {}; | |
|
87 | DateTimeRange m_Range { INVALID_RANGE }; | |
|
86 | 88 | }; |
|
87 | 89 | |
|
88 | 90 | using SyncGroupId = QUuid; |
|
89 | 91 | using SyncGroupsPool = std::map<SyncGroupId, SyncGroup>; |
|
90 | 92 | |
|
91 | 93 | /** |
|
92 | 94 | * Defines a current state during a fuzzing state. It contains all the variables manipulated during |
|
93 | 95 | * the test, as well as the synchronization status of these variables. |
|
94 | 96 | */ |
|
95 |
struct FuzzingState |
|
|
96 | const SyncGroup &syncGroup(SyncGroupId id) const; | |
|
97 |
SyncGroup |
|
|
97 | struct FuzzingState | |
|
98 | { | |
|
99 | const SyncGroup& syncGroup(SyncGroupId id) const; | |
|
100 | SyncGroup& syncGroup(SyncGroupId id); | |
|
98 | 101 | |
|
99 |
const VariableState |
|
|
100 |
VariableState |
|
|
102 | const VariableState& variableState(VariableId id) const; | |
|
103 | VariableState& variableState(VariableId id); | |
|
101 | 104 | |
|
102 | 105 | /// @return the identifier of the synchronization group in which the variable passed in |
|
103 | 106 | /// parameter is located. If the variable is not in any group, returns an invalid identifier |
|
104 | 107 | SyncGroupId syncGroupId(VariableId variableId) const; |
|
105 | 108 | |
|
106 | 109 | /// @return the set of synchronization group identifiers |
|
107 | 110 | std::vector<SyncGroupId> syncGroupsIds() const; |
|
108 | 111 | |
|
109 | 112 | /// Updates fuzzing state according to a variable synchronization |
|
110 | 113 | /// @param variableId the variable that is synchronized |
|
111 | 114 | /// @param syncGroupId the synchronization group |
|
112 | 115 | void synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId); |
|
113 | 116 | |
|
114 | 117 | /// Updates fuzzing state according to a variable desynchronization |
|
115 | 118 | /// @param variableId the variable that is desynchronized |
|
116 | 119 | /// @param syncGroupId the synchronization group from which to remove the variable |
|
117 | 120 | void desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId); |
|
118 | 121 | |
|
119 | 122 | /// Updates the range of a variable and all variables to which it is synchronized |
|
120 | 123 | /// @param the variable for which to affect the range |
|
121 | 124 | /// @param the range to affect |
|
122 |
void updateRanges(VariableId variableId, const DateTimeRange |
|
|
125 | void updateRanges(VariableId variableId, const DateTimeRange& newRange); | |
|
123 | 126 | |
|
124 | 127 | VariablesPool m_VariablesPool; |
|
125 | 128 | SyncGroupsPool m_SyncGroupsPool; |
|
126 | 129 | }; |
|
127 | 130 | |
|
128 | 131 | #endif // SCIQLOP_FUZZINGDEFS_H |
@@ -1,31 +1,32 | |||
|
1 | 1 | #ifndef SCIQLOP_COSINUSPROVIDER_H |
|
2 | 2 | #define SCIQLOP_COSINUSPROVIDER_H |
|
3 | 3 | |
|
4 | 4 | #include "MockPluginGlobal.h" |
|
5 | 5 | |
|
6 | 6 | #include <Data/IDataProvider.h> |
|
7 | 7 | |
|
8 | 8 | #include <QLoggingCategory> |
|
9 | 9 | #include <QUuid> |
|
10 | 10 | |
|
11 | 11 | #include <QHash> |
|
12 | 12 | |
|
13 | 13 | /** |
|
14 | 14 | * @brief The CosinusProvider class is an example of how a data provider can generate data |
|
15 | 15 | */ |
|
16 |
class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider |
|
|
16 | class SCIQLOP_MOCKPLUGIN_EXPORT CosinusProvider : public IDataProvider | |
|
17 | { | |
|
17 | 18 | public: |
|
18 | 19 | std::shared_ptr<IDataProvider> clone() const override; |
|
19 | 20 | |
|
20 |
virtual |
|
|
21 | virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters) override; | |
|
21 | 22 | |
|
22 | 23 | private: |
|
23 | std::shared_ptr<IDataSeries> | |
|
24 |
|
|
|
24 | std::shared_ptr<IDataSeries> retrieveData( | |
|
25 | QUuid acqIdentifier, const DateTimeRange& dataRangeRequested, const QVariantHash& data); | |
|
25 | 26 | |
|
26 |
|
|
|
27 | TimeSeries::ITimeSerie* _generate(const DateTimeRange& range, const QVariantHash& metaData); | |
|
27 | 28 | |
|
28 | 29 | QHash<QUuid, bool> m_VariableToEnableProvider; |
|
29 | 30 | }; |
|
30 | 31 | |
|
31 | 32 | #endif // SCIQLOP_COSINUSPROVIDER_H |
@@ -1,204 +1,87 | |||
|
1 | 1 | #include "CosinusProvider.h" |
|
2 | 2 | #include "MockDefs.h" |
|
3 | 3 | |
|
4 | 4 | #include <Data/DataProviderParameters.h> |
|
5 |
#include <Data/ScalarSerie |
|
|
6 |
#include <Data/SpectrogramSerie |
|
|
7 |
#include <Data/VectorSerie |
|
|
5 | #include <Data/ScalarTimeSerie.h> | |
|
6 | #include <Data/SpectrogramTimeSerie.h> | |
|
7 | #include <Data/VectorTimeSerie.h> | |
|
8 | 8 | |
|
9 | 9 | #include <cmath> |
|
10 | 10 | #include <set> |
|
11 | 11 | |
|
12 | 12 | #include <QFuture> |
|
13 | 13 | #include <QThread> |
|
14 | 14 | #include <QtConcurrent/QtConcurrent> |
|
15 | 15 | |
|
16 | 16 | |
|
17 |
namespace |
|
|
17 | namespace | |
|
18 | { | |
|
18 | 19 | |
|
19 | 20 | /// Number of bands generated for a spectrogram |
|
20 | 21 | const auto SPECTROGRAM_NUMBER_BANDS = 30; |
|
21 | 22 | |
|
22 | 23 | /// Bands for which to generate NaN values for a spectrogram |
|
23 | const auto SPECTROGRAM_NAN_BANDS = std::set<int>{1, 3, 10, 20}; | |
|
24 | const auto SPECTROGRAM_NAN_BANDS = std::set<int> { 1, 3, 10, 20 }; | |
|
24 | 25 | |
|
25 | 26 | /// Bands for which to generate zeros for a spectrogram |
|
26 | const auto SPECTROGRAM_ZERO_BANDS = std::set<int>{2, 15, 19, 29}; | |
|
27 | ||
|
28 | /// Abstract cosinus type | |
|
29 | struct ICosinusType { | |
|
30 | virtual ~ICosinusType() = default; | |
|
31 | /// @return the number of components generated for the type | |
|
32 | virtual std::size_t componentCount() const = 0; | |
|
33 | /// @return the data series created for the type | |
|
34 | virtual IDataSeries* createDataSeries(std::vector<double> xAxisData, | |
|
35 | std::vector<double> valuesData) const = 0; | |
|
36 | /// Generates values (one value per component) | |
|
37 | /// @param x the x-axis data used to generate values | |
|
38 | /// @param values the vector in which to insert the generated values | |
|
39 | /// @param dataIndex the index of insertion of the generated values | |
|
40 | /// | |
|
41 | virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0; | |
|
42 | }; | |
|
43 | ||
|
44 | struct ScalarCosinus : public ICosinusType { | |
|
45 | std::size_t componentCount() const override { return 1; } | |
|
46 | ||
|
47 | IDataSeries* createDataSeries(std::vector<double> xAxisData, | |
|
48 | std::vector<double> valuesData) const override | |
|
49 | { | |
|
50 | return new ScalarSeries(std::move(xAxisData), std::move(valuesData), | |
|
51 | Unit{QStringLiteral("t"), true}, Unit{}); | |
|
52 | } | |
|
53 | ||
|
54 | void generateValues(double x, std::vector<double> &values, int dataIndex) const override | |
|
55 | { | |
|
56 | values[dataIndex] = std::cos(x); | |
|
57 | } | |
|
58 | }; | |
|
59 | ||
|
60 | struct SpectrogramCosinus : public ICosinusType { | |
|
61 | /// Ctor with y-axis | |
|
62 | explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit) | |
|
63 | : m_YAxisData{std::move(yAxisData)}, | |
|
64 | m_YAxisUnit{std::move(yAxisUnit)}, | |
|
65 | m_ValuesUnit{std::move(valuesUnit)} | |
|
66 | { | |
|
67 | } | |
|
68 | ||
|
69 | std::size_t componentCount() const override { return m_YAxisData.size(); } | |
|
70 | ||
|
71 | IDataSeries* createDataSeries(std::vector<double> xAxisData, | |
|
72 | std::vector<double> valuesData) const override | |
|
73 | { | |
|
74 | return new SpectrogramSeries( | |
|
75 | std::move(xAxisData), m_YAxisData, std::move(valuesData), | |
|
76 | Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit); | |
|
77 | } | |
|
78 | ||
|
79 | void generateValues(double x, std::vector<double> &values, int dataIndex) const override | |
|
80 | { | |
|
81 | auto componentCount = this->componentCount(); | |
|
82 | for (int i = 0; i < componentCount; ++i) { | |
|
83 | auto y = m_YAxisData[i]; | |
|
84 | ||
|
85 | double value; | |
|
86 | ||
|
87 | // if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) { | |
|
88 | // value = 0.; | |
|
89 | // } | |
|
90 | // else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) { | |
|
91 | // value = std::numeric_limits<double>::quiet_NaN(); | |
|
92 | // } | |
|
93 | // else | |
|
94 | { | |
|
95 | // Generates value for non NaN/zero bands | |
|
96 | //auto r = 3 * std::sqrt(x * x + y * y) + 1e-2; | |
|
97 | //value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r); | |
|
98 | value = x + 10*y; | |
|
99 | } | |
|
100 | ||
|
101 | values[componentCount * dataIndex + i] = value; | |
|
102 | } | |
|
103 | } | |
|
104 | ||
|
105 | std::vector<double> m_YAxisData; | |
|
106 | Unit m_YAxisUnit; | |
|
107 | Unit m_ValuesUnit; | |
|
108 | }; | |
|
109 | ||
|
110 | struct VectorCosinus : public ICosinusType { | |
|
111 | std::size_t componentCount() const override { return 3; } | |
|
27 | const auto SPECTROGRAM_ZERO_BANDS = std::set<int> { 2, 15, 19, 29 }; | |
|
112 | 28 | |
|
113 | IDataSeries* createDataSeries(std::vector<double> xAxisData, | |
|
114 | std::vector<double> valuesData) const override | |
|
115 | { | |
|
116 | return new VectorSeries(std::move(xAxisData), std::move(valuesData), | |
|
117 | Unit{QStringLiteral("t"), true}, Unit{}); | |
|
118 | } | |
|
119 | ||
|
120 | void generateValues(double x, std::vector<double> &values, int dataIndex) const override | |
|
121 | { | |
|
122 | // Generates value for each component: cos(x), cos(x)/2, cos(x)/3 | |
|
123 | auto xValue = std::cos(x); | |
|
124 | auto componentCount = this->componentCount(); | |
|
125 | for (auto i = 0; i < componentCount; ++i) { | |
|
126 | values[componentCount * dataIndex + i] = xValue / (i + 1); | |
|
127 | } | |
|
128 | } | |
|
129 | }; | |
|
130 | ||
|
131 | /// Converts string to cosinus type | |
|
132 | /// @return the cosinus type if the string could be converted, nullptr otherwise | |
|
133 | std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept | |
|
134 | { | |
|
135 | if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) { | |
|
136 | return std::make_unique<ScalarCosinus>(); | |
|
137 | } | |
|
138 | else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) { | |
|
139 | // Generates default y-axis data for spectrogram [0., 1., 2., ...] | |
|
140 | std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS); | |
|
141 | std::iota(yAxisData.begin(), yAxisData.end(), 1.); | |
|
142 | for (auto & v:yAxisData) | |
|
143 | { | |
|
144 | v = std::pow(2,v); | |
|
145 | } | |
|
146 | return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"}, | |
|
147 | Unit{"eV/(cm^2-s-sr-eV)"}); | |
|
148 | } | |
|
149 | else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) { | |
|
150 | return std::make_unique<VectorCosinus>(); | |
|
151 | } | |
|
152 | else { | |
|
153 | return nullptr; | |
|
154 | } | |
|
155 | } | |
|
156 | 29 | |
|
157 | 30 | } // namespace |
|
158 | 31 | |
|
159 | 32 | std::shared_ptr<IDataProvider> CosinusProvider::clone() const |
|
160 | 33 | { |
|
161 | 34 | // No copy is made in clone |
|
162 | 35 | return std::make_shared<CosinusProvider>(); |
|
163 | 36 | } |
|
164 | 37 | |
|
165 | IDataSeries *CosinusProvider::_generate(const DateTimeRange &range, const QVariantHash &metaData) | |
|
38 | TimeSeries::ITimeSerie* CosinusProvider::_generate( | |
|
39 | const DateTimeRange& range, const QVariantHash& metaData) | |
|
166 | 40 | { |
|
167 | auto dataIndex = 0; | |
|
168 | ||
|
169 | 41 | // Retrieves cosinus type |
|
170 | 42 | auto typeVariant = metaData.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE); |
|
171 | auto type = cosinusType(typeVariant.toString()); | |
|
172 | 43 | auto freqVariant = metaData.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE); |
|
44 | const auto fs = 200.; | |
|
173 | 45 | double freq = freqVariant.toDouble(); |
|
174 | 46 | double start = std::ceil(range.m_TStart * freq); |
|
175 | 47 | double end = std::floor(range.m_TEnd * freq); |
|
176 |
if (end < start) |
|
|
48 | if (end < start) | |
|
49 | { | |
|
177 | 50 | std::swap(start, end); |
|
178 | 51 | } |
|
179 | 52 | std::size_t dataCount = static_cast<std::size_t>(end - start + 1); |
|
180 | std::size_t componentCount = type->componentCount(); | |
|
181 | ||
|
182 | auto xAxisData = std::vector<double>{}; | |
|
183 | xAxisData.resize(dataCount); | |
|
184 | ||
|
185 | auto valuesData = std::vector<double>{}; | |
|
186 | valuesData.resize(dataCount * componentCount); | |
|
187 | ||
|
188 | int progress = 0; | |
|
189 | auto progressEnd = dataCount; | |
|
190 | for (auto time = start; time <= end; ++time, ++dataIndex) | |
|
53 | if (typeVariant.toString() == QStringLiteral("scalar")) | |
|
191 | 54 | { |
|
192 | const auto x = time / freq; | |
|
193 | xAxisData[dataIndex] = x; | |
|
194 | // Generates values (depending on the type) | |
|
195 | type->generateValues(x, valuesData, dataIndex); | |
|
55 | auto ts = new ScalarTimeSerie(dataCount); | |
|
56 | std::generate( | |
|
57 | std::begin(*ts), std::end(*ts), [range, freq, fs, dt = 1. / freq, i = 0.]() mutable { | |
|
58 | auto t = range.m_TStart + i * dt; | |
|
59 | i++; | |
|
60 | return std::pair<double, double> { t, std::cos(2 * 3.14 * freq / fs * t) }; | |
|
61 | }); | |
|
62 | return ts; | |
|
196 | 63 | } |
|
197 | return type->createDataSeries(std::move(xAxisData), std::move(valuesData)); | |
|
64 | if (typeVariant.toString() == QStringLiteral("vector")) | |
|
65 | { | |
|
66 | auto ts = new VectorTimeSerie(dataCount); | |
|
67 | std::generate( | |
|
68 | std::begin(*ts), std::end(*ts), [range, freq, fs, dt = 1. / freq, i = 0.]() mutable { | |
|
69 | auto t = range.m_TStart + i * dt; | |
|
70 | i++; | |
|
71 | return std::pair<double, VectorTimeSerie::raw_value_type> { t, | |
|
72 | { std::cos(2 * 3.14 * freq / fs * t), std::sin(2 * 3.14 * freq / fs * t), | |
|
73 | std::cos(2 * 3.14 * freq / fs * t) * std::sin(2 * 3.14 * freq / fs * t) } }; | |
|
74 | }); | |
|
75 | return ts; | |
|
76 | } | |
|
77 | if (typeVariant.toString() == QStringLiteral("spectrogram")) | |
|
78 | { | |
|
79 | return nullptr; | |
|
80 | } | |
|
81 | return nullptr; | |
|
198 | 82 | } |
|
199 | 83 | |
|
200 |
|
|
|
84 | TimeSeries::ITimeSerie* CosinusProvider::getData(const DataProviderParameters& parameters) | |
|
201 | 85 | { |
|
202 | 86 | return _generate(parameters.m_Range, parameters.m_Data); |
|
203 | 87 | } |
|
204 |
@@ -1,85 +1,86 | |||
|
1 | 1 | /*------------------------------------------------------------------------------ |
|
2 | 2 | -- This file is a part of the SciQLOP Software |
|
3 | 3 | -- Copyright (C) 2018, Plasma Physics Laboratory - CNRS |
|
4 | 4 | -- |
|
5 | 5 | -- This program is free software; you can redistribute it and/or modify |
|
6 | 6 | -- it under the terms of the GNU General Public License as published by |
|
7 | 7 | -- the Free Software Foundation; either version 2 of the License, or |
|
8 | 8 | -- (at your option) any later version. |
|
9 | 9 | -- |
|
10 | 10 | -- This program is distributed in the hope that it will be useful, |
|
11 | 11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | 12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 | 13 | -- GNU General Public License for more details. |
|
14 | 14 | -- |
|
15 | 15 | -- You should have received a copy of the GNU General Public License |
|
16 | 16 | -- along with this program; if not, write to the Free Software |
|
17 | 17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 | 18 | -------------------------------------------------------------------------------*/ |
|
19 | 19 | /*-- Author : Alexis Jeandet |
|
20 | 20 | -- Mail : alexis.jeandet@member.fsf.org |
|
21 | 21 | ----------------------------------------------------------------------------*/ |
|
22 | #include <string> | |
|
23 | #include <sstream> | |
|
24 | 22 | #include <memory> |
|
23 | #include <sstream> | |
|
24 | #include <string> | |
|
25 | 25 | |
|
26 |
#include <pybind11/ |
|
|
27 | #include <pybind11/operators.h> | |
|
26 | #include <pybind11/chrono.h> | |
|
28 | 27 | #include <pybind11/embed.h> |
|
29 | 28 | #include <pybind11/numpy.h> |
|
30 |
#include <pybind11/ |
|
|
29 | #include <pybind11/operators.h> | |
|
30 | #include <pybind11/pybind11.h> | |
|
31 | 31 | |
|
32 | #include <Common/DateUtils.h> | |
|
33 | #include <Data/DataSeriesType.h> | |
|
34 | #include <Data/DateTimeRange.h> | |
|
32 | 35 | #include <SqpApplication.h> |
|
33 | #include <Variable/VariableController2.h> | |
|
34 | 36 | #include <Time/TimeController.h> |
|
35 | #include <Data/DateTimeRange.h> | |
|
36 | #include <Data/DataSeriesType.h> | |
|
37 | #include <Common/DateUtils.h> | |
|
38 | #include <Variable/Variable.h> | |
|
39 | #include <Data/ScalarSeries.h> | |
|
40 | #include <Data/VectorSeries.h> | |
|
37 | #include <Variable/VariableController2.h> | |
|
41 | 38 | |
|
42 | #include <MockPlugin.h> | |
|
43 | 39 | #include <CosinusProvider.h> |
|
40 | #include <MockPlugin.h> | |
|
44 | 41 | |
|
45 | 42 | #include <QFile> |
|
46 | 43 | |
|
47 | #include <pywrappers_common.h> | |
|
48 | 44 | #include <CoreWrappers.h> |
|
49 | ||
|
45 | #include <pywrappers_common.h> | |
|
50 | 46 | |
|
51 | 47 | |
|
52 | 48 | using namespace std::chrono; |
|
53 | 49 | namespace py = pybind11; |
|
54 | 50 | |
|
55 | 51 | |
|
56 | ||
|
57 | PYBIND11_MODULE(pytestmockplugin, m){ | |
|
52 | PYBIND11_MODULE(pytestmockplugin, m) | |
|
53 | { | |
|
58 | 54 | |
|
59 | 55 | int argc = 0; |
|
60 |
char |
|
|
56 | char** argv = nullptr; | |
|
61 | 57 | SqpApplication::setOrganizationName("LPP"); |
|
62 | 58 | SqpApplication::setOrganizationDomain("lpp.fr"); |
|
63 | 59 | SqpApplication::setApplicationName("SciQLop"); |
|
64 | 60 | static SqpApplication app(argc, argv); |
|
65 | 61 | |
|
66 | 62 | auto qtmod = py::module::import("sciqlopqt"); |
|
67 | 63 | auto sciqlopmod = py::module::import("pysciqlopcore"); |
|
68 | 64 | |
|
69 | 65 | m.doc() = ""; |
|
70 | 66 | |
|
71 |
py::class_<VariableController2>(m, "VariableController2") |
|
|
72 | std::shared_ptr<IDataProvider> provider, const DateTimeRange& range){ | |
|
73 | return sqpApp->variableController().createVariable(name, {{"cosinusType", "spectrogram"}, {"cosinusFrequency", "0.1"}}, provider, range); | |
|
67 | py::class_<VariableController2>(m, "VariableController2") | |
|
68 | .def_static("createVariable", | |
|
69 | [](const QString& name, std::shared_ptr<IDataProvider> provider, | |
|
70 | const DateTimeRange& range) { | |
|
71 | return sqpApp->variableController().createVariable(name, | |
|
72 | { { "cosinusType", "spectrogram" }, { "cosinusFrequency", "0.1" } }, provider, | |
|
73 | range); | |
|
74 | }); | |
|
75 | ||
|
76 | py::class_<TimeController>(m, "TimeController").def_static("setTime", [](DateTimeRange range) { | |
|
77 | sqpApp->timeController().setDateTimeRange(range); | |
|
74 | 78 | }); |
|
75 | 79 | |
|
76 | py::class_<TimeController>(m,"TimeController") | |
|
77 | .def_static("setTime", [](DateTimeRange range){sqpApp->timeController().setDateTimeRange(range);}); | |
|
78 | ||
|
79 | 80 | auto mock_provider = std::make_shared<CosinusProvider>(); |
|
80 |
m.def("mock_provider",[mock_provider](){return mock_provider;}, |
|
|
81 | ||
|
82 | py::class_<CosinusProvider, std::shared_ptr<CosinusProvider>, IDataProvider>(m, "CosinusProvider"); | |
|
81 | m.def("mock_provider", [mock_provider]() { return mock_provider; }, | |
|
82 | py::return_value_policy::copy); | |
|
83 | 83 | |
|
84 | py::class_<CosinusProvider, std::shared_ptr<CosinusProvider>, IDataProvider>( | |
|
85 | m, "CosinusProvider"); | |
|
84 | 86 | } |
|
85 |
General Comments 0
You need to be logged in to leave comments.
Login now