diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a4f932bc..1ceff90cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -528,6 +528,8 @@ set(QT_VERSION "6.5.2" CACHE STRING "Qt target version, defaults to 6.5.2") # For AboutBox, but also validates that the version is valid string(TIMESTAMP CURRENT_YEAR "%Y") +string(REGEX MATCH "^([0-9]+)" + QT_VERSION_MAJOR ${QT_VERSION}) string(REGEX MATCH "^([0-9]+\\.[0-9]+)" QT_VERSION_MAJOR_MINOR ${QT_VERSION}) if(NOT QT_VERSION_MAJOR_MINOR) @@ -544,7 +546,7 @@ message(STATUS "QT_INSTALL_DIR=${QT_INSTALL_DIR}") find_package(Qt6 ${QT_VERSION} COMPONENTS CoreTools GuiTools WidgetsTools QmlTools WebEngineCoreTools REQUIRED PATHS ${QT_INSTALL_DIR} NO_DEFAULT_PATH) -find_package(Qt6 ${QT_VERSION} COMPONENTS Core Core5Compat Gui Widgets Sql Svg Network Xml Concurrent PrintSupport Quick QuickWidgets Qml WebChannel Positioning WebEngineCore WebEngineWidgets Charts REQUIRED PATHS ${QT_INSTALL_DIR} NO_DEFAULT_PATH) +find_package(Qt6 ${QT_VERSION} COMPONENTS Core Core5Compat Gui Widgets Sql Svg Network Xml Concurrent OpenGL OpenGLWidgets Positioning PrintSupport Quick QuickWidgets Qml WebChannel WebEngineCore WebEngineWidgets REQUIRED PATHS ${QT_INSTALL_DIR} NO_DEFAULT_PATH) find_package(Qt6LinguistTools ${QT_VERSION} REQUIRED PATHS ${QT_INSTALL_DIR} NO_DEFAULT_PATH) @@ -563,7 +565,6 @@ find_file(qweb_resources_200 NAMES qtwebengine_resources_200p.pak PATHS "${QT_IN # QT_WEB_LIBS are linked by OS App and openstudio_lib but not by openstudio_modeleditor.so or openstudio_modeleditor list(APPEND QT_WEB_LIBS Qt6::WebEngineCore) list(APPEND QT_WEB_LIBS Qt6::WebEngineWidgets) -list(APPEND QT_WEB_LIBS Qt6::Charts) set_target_properties(${QT_WEB_LIBS} PROPERTIES INTERFACE_LINK_LIBRARIES "") if(NOT APPLE) @@ -658,10 +659,43 @@ if(UNIX) list(APPEND QT_INCLUDES ${Qt6XcbQpa_INCLUDE_DIRS}) endif() -set(CMAKE_AUTOMOC OFF) - +####################### JKQTPlotter ###################### +# Make JKQTPlotter available after finding Qt include(FetchContent) +# Build it statically +set(OLD_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) +set(BUILD_SHARED_LIBS OFF) + +set(JKQtPlotter_BUILD_EXAMPLES OFF) +set(JKQtPlotter_BUILD_LIB_JKQTFASTPLOTTER OFF) + +# Force finding the same Qt +find_package(QT NAMES Qt6 COMPONENTS Core Gui Widgets PrintSupport Svg Xml OpenGl REQUIRED PATHS ${QT_INSTALL_DIR} NO_DEFAULT_PATH) + +FetchContent_Declare(JKQTPlotter${QT_VERSION_MAJOR} + GIT_REPOSITORY https://github.com/jkriege2/JKQtPlotter.git + # GIT_TAG v5.0.0 # This is unreleased, but FetchContent support was added after v4.0.3 +) + +FetchContent_MakeAvailable(JKQTPlotter${QT_VERSION_MAJOR}) + +if (MSVC) + target_compile_definitions(JKQTPlotter${QT_VERSION_MAJOR} PRIVATE + _USE_MATH_DEFINES # To enable M_PI, M_E,.. + DNOMINMAX # To Prevent Errors with min() and max() + _CRT_NO_VA_START_VALIDATION # To fix error: C2338: va_start argument must not have reference type and must not be parenthesized + ) + target_compile_options(JKQTPlotter${QT_VERSION_MAJOR} PRIVATE /EHsc /wd4018) +endif() + +set(BUILD_SHARED_LIBS ${OLD_BUILD_SHARED_LIBS}) + +########################################################## + +set(CMAKE_AUTOMOC OFF) + +# Get the OpenStudio Coalition Measures repo FetchContent_Declare( openstudio-coalition-measures GIT_REPOSITORY https://github.com/openstudiocoalition/openstudio-coalition-measures.git diff --git a/src/openstudio_app/AboutBox.hpp.in b/src/openstudio_app/AboutBox.hpp.in index e3546ccab..f0e4acbde 100644 --- a/src/openstudio_app/AboutBox.hpp.in +++ b/src/openstudio_app/AboutBox.hpp.in @@ -9,8 +9,6 @@

OpenStudio is a cross-platform tool to support whole building energy and daylight modeling using EnergyPlus and Radiance.

\

OpenStudio uses the following QT modules (version ${QT_VERSION}) that are dynamically linked using GNU Lesser General Public License (LGPL): \ Qt6Core, Qt6Core5Compat Qt6Widgets, Qt6Network, Qt6Concurrent, Qt6PrintSupport, Qt6Gui, Qt6Quick, Qt6QuickWidgets, Qt6Qml, Qt6QmlModels, Qt6WebChannel, Qt6Positioning, Qt6WebEngine, Qt6WebEngineWidgets, QtWebEngineCore, Qt6DBus, Qt6Xml, Qt6Svg, Qt6OpenGL, Qt6OpenGLWidgets

\ -

And these Qt modules that are dynamically linked using GNU General Public License (GPL): \ -Qt6Charts

\

For information on QT, please refer to QT

\

A copy of the GPL 3.0 and LGPL 3.0 are included in the root path of your installation directory.

" #endif // OPENSTUDIOAPP_ABOUTBOX diff --git a/src/openstudio_lib/CMakeLists.txt b/src/openstudio_lib/CMakeLists.txt index 917c074b2..522b1b965 100644 --- a/src/openstudio_lib/CMakeLists.txt +++ b/src/openstudio_lib/CMakeLists.txt @@ -774,7 +774,9 @@ set(${target_name}_depends openstudio::openstudiolib ${QT_LIBS} ${QT_WEB_LIBS} + JKQTPlotter${QT_VERSION_MAJOR}::JKQTPlotter${QT_VERSION_MAJOR} ) + if(WIN32) list(APPEND ${target_name}_depends qtwinmigrate) endif() diff --git a/src/openstudio_lib/HVACSystemsView.cpp b/src/openstudio_lib/HVACSystemsView.cpp index 2ff14535f..40e3f9473 100644 --- a/src/openstudio_lib/HVACSystemsView.cpp +++ b/src/openstudio_lib/HVACSystemsView.cpp @@ -35,10 +35,9 @@ #include #include -#include -#include -#include -#include +#include +#include + #include namespace openstudio { @@ -687,34 +686,54 @@ OAResetSPMView::OAResetSPMView(const model::SetpointManagerOutdoorAirReset& spm) auto* title = new QLabel(text); mainVLayout->addWidget(title); - auto* series = new QLineSeries; + // Create a JKQTPlotter widget + JKQTPlotter* plotter = new JKQTPlotter(); + plotter->setPlotUpdateEnabled(false); + JKQTPDatastore* ds = plotter->getDatastore(); + + // Generate the data for the plot + QVector x, y; const auto lowOATemp = spm.outdoorLowTemperature(); // 5 const auto highOATemp = spm.outdoorHighTemperature(); // 30 const auto lowVal = spm.setpointatOutdoorLowTemperature(); // 25 const auto highVal = spm.setpointatOutdoorHighTemperature(); // 18 - series->append(lowOATemp - 5, lowVal); - series->append(lowOATemp, lowVal); - series->append(highOATemp, highVal); - series->append(highOATemp + 5, highVal); - - auto* chart = new QChart; - chart->legend()->hide(); - chart->addSeries(series); - chart->createDefaultAxes(); - auto* xAxis = chart->axes(Qt::Horizontal)[0]; - xAxis->setTitleText("Outdoor Air Temperature [C]"); - auto* yAxis = chart->axes(Qt::Vertical)[0]; - yAxis->setTitleText("Setpoint Temperature [C]"); - yAxis->setRange(std::min(lowVal, highVal) - 2, std::max(lowVal, highVal) + 2); - - chart->setTitle("Setpoint Outdoor Air Temp Reset"); - chart->setAnimationOptions(QChart::SeriesAnimations); - - auto* m_defaultChartView = new QChartView(chart, this); - m_defaultChartView->setRenderHint(QPainter::Antialiasing); - m_defaultChartView->setMinimumSize(400, 400); - mainVLayout->addWidget(m_defaultChartView); + x.append(lowOATemp - 5); + y.append(lowVal); + x.append(lowOATemp); + y.append(lowVal); + x.append(highOATemp); + y.append(highVal); + x.append(highOATemp + 5); + y.append(highVal); + + // Add data to the datastore + size_t columnX = ds->addCopiedColumn(x, "x"); + size_t columnY = ds->addCopiedColumn(y, "y"); + + JKQTPXYLineGraph* graph = new JKQTPXYLineGraph(plotter); + graph->setXColumn(columnX); + graph->setYColumn(columnY); + graph->setTitle("Setpoint Outdoor Air Temp Reset"); + + plotter->getXAxis()->setAxisLabel("Outdoor Air Temperature [C]"); + plotter->getYAxis()->setAxisLabel("Setpoint Temperature [C]"); + plotter->setMinimumSize(400, 400); + plotter->setMaximumSize(600, 400); + plotter->setToolbarEnabled(false); + plotter->clearAllMouseWheelActions(); + plotter->clearAllRegisteredMouseDoubleClickActions(); + plotter->clearAllRegisteredMouseDragActions(); + plotter->getPlotter()->setUseAntiAliasingForGraphs(false); + plotter->getPlotter()->setUseAntiAliasingForSystem(false); + plotter->getPlotter()->setUseAntiAliasingForText(false); + plotter->getPlotter()->setPlotLabel("Setpoint Follow Outdoor Air Temperature"); + plotter->addGraph(graph); + plotter->zoomToFit(); + plotter->setPlotUpdateEnabled(true); + plotter->redrawPlot(); + + mainVLayout->addWidget(plotter); mainVLayout->addStretch(); } @@ -735,34 +754,54 @@ SystemNodeResetSPMView::SystemNodeResetSPMView(const model::SetpointManagerSyste auto* title = new QLabel(text); mainVLayout->addWidget(title); - auto* series = new QLineSeries; + // Create a JKQTPlotter widget + JKQTPlotter* plotter = new JKQTPlotter(); + plotter->setPlotUpdateEnabled(false); + JKQTPDatastore* ds = plotter->getDatastore(); + + // Generate the data for the plot + QVector x, y; const auto lowOATemp = spm.lowReferenceTemperature(); // 5 const auto highOATemp = spm.highReferenceTemperature(); // 30 const auto lowVal = spm.setpointatLowReferenceTemperature(); // 25 const auto highVal = spm.setpointatHighReferenceTemperature(); // 18 - series->append(lowOATemp - 5, lowVal); - series->append(lowOATemp, lowVal); - series->append(highOATemp, highVal); - series->append(highOATemp + 5, highVal); - - auto* chart = new QChart; - chart->legend()->hide(); - chart->addSeries(series); - chart->createDefaultAxes(); - auto* xAxis = chart->axes(Qt::Horizontal)[0]; - xAxis->setTitleText("System Node Temperature [C]"); - auto* yAxis = chart->axes(Qt::Vertical)[0]; - yAxis->setTitleText("Setpoint Temperature [C]"); - yAxis->setRange(std::min(lowVal, highVal) - 2, std::max(lowVal, highVal) + 2); - - chart->setTitle("Setpoint System Node Reset Temperature"); - chart->setAnimationOptions(QChart::SeriesAnimations); - - auto* m_defaultChartView = new QChartView(chart, this); - m_defaultChartView->setRenderHint(QPainter::Antialiasing); - m_defaultChartView->setMinimumSize(400, 400); - mainVLayout->addWidget(m_defaultChartView); + x.append(lowOATemp - 5); + y.append(lowVal); + x.append(lowOATemp); + y.append(lowVal); + x.append(highOATemp); + y.append(highVal); + x.append(highOATemp + 5); + y.append(highVal); + + // Add data to the datastore + size_t columnX = ds->addCopiedColumn(x, "x"); + size_t columnY = ds->addCopiedColumn(y, "y"); + + JKQTPXYLineGraph* graph = new JKQTPXYLineGraph(plotter); + graph->setXColumn(columnX); + graph->setYColumn(columnY); + graph->setTitle("Setpoint System Node Reset Temperature"); + + plotter->getXAxis()->setAxisLabel("System Node Temperature [C]"); + plotter->getYAxis()->setAxisLabel("Setpoint Temperature [C]"); + plotter->setMinimumSize(400, 400); + plotter->setMaximumSize(600, 400); + plotter->setToolbarEnabled(false); + plotter->clearAllMouseWheelActions(); + plotter->clearAllRegisteredMouseDoubleClickActions(); + plotter->clearAllRegisteredMouseDragActions(); + plotter->getPlotter()->setUseAntiAliasingForGraphs(false); + plotter->getPlotter()->setUseAntiAliasingForSystem(false); + plotter->getPlotter()->setUseAntiAliasingForText(false); + plotter->getPlotter()->setPlotLabel("Setpoint Follow System Node Temperature"); + plotter->addGraph(graph); + plotter->zoomToFit(); + plotter->setPlotUpdateEnabled(true); + plotter->redrawPlot(); + + mainVLayout->addWidget(plotter); mainVLayout->addStretch(); } @@ -799,40 +838,54 @@ FollowOATempSPMView::FollowOATempSPMView(const model::SetpointManagerFollowOutdo new QLabel(QString("Supply temperature follows the %1 temperature with an offset of %2 C.").arg(refTempType, QString::number(offset))); mainVLayout->addWidget(followOATempSPMlabel); - auto* series = new QLineSeries; - series->setName("Setpoint Temperature"); - auto* seriesOA = new QLineSeries; - seriesOA->setName(refTempType); - QRgb color1 = qRgb(255, 0, 0); - QPen pen1(color1); - pen1.setStyle(Qt::DotLine); - pen1.setWidth(1); - seriesOA->setPen(pen1); + // Create a JKQTPlotter widget + JKQTPlotter* plotter = new JKQTPlotter(); + plotter->setPlotUpdateEnabled(false); + JKQTPDatastore* ds = plotter->getDatastore(); + + // Generate the data for the plot + QVector x, y, yOA; std::vector xVals{-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40}; - for (const auto& x : xVals) { - double y = std::clamp(x + offset, minVal, maxVal); - series->append(x, y); - seriesOA->append(x, x); + for (const auto& xVal : xVals) { + x.append(xVal); + y.append(std::clamp(xVal + offset, minVal, maxVal)); + yOA.append(xVal); } - auto* chart = new QChart; - chart->legend()->hide(); - chart->addSeries(series); - chart->addSeries(seriesOA); - chart->createDefaultAxes(); - auto* xAxis = chart->axes(Qt::Horizontal)[0]; - xAxis->setTitleText(QString("%1 Temperature [C]").arg(refTempType)); - auto* yAxis = chart->axes(Qt::Vertical)[0]; - yAxis->setTitleText("Setpoint Temperature [C]"); - - chart->setTitle("Setpoint Follow Outdoor Air Temperature"); - chart->setAnimationOptions(QChart::SeriesAnimations); - - auto* m_defaultChartView = new QChartView(chart, this); - m_defaultChartView->setRenderHint(QPainter::Antialiasing); - m_defaultChartView->setMinimumSize(400, 400); - mainVLayout->addWidget(m_defaultChartView); + // Add data to the datastore + size_t columnX = ds->addCopiedColumn(x, "x"); + size_t columnY = ds->addCopiedColumn(y, "y"); + size_t columnYOA = ds->addCopiedColumn(yOA, "yOA"); + + JKQTPXYLineGraph* graph1 = new JKQTPXYLineGraph(plotter); + graph1->setXColumn(columnX); + graph1->setYColumn(columnY); + graph1->setTitle("Setpoint Temperature"); + JKQTPXYLineGraph* graph2 = new JKQTPXYLineGraph(plotter); + graph2->setXColumn(columnX); + graph2->setYColumn(columnYOA); + graph2->setTitle(refTempType); + + plotter->getXAxis()->setAxisLabel(QString("%1 Temperature [C]").arg(refTempType)); + plotter->getYAxis()->setAxisLabel("Setpoint Temperature [C]"); + plotter->setMinimumSize(400, 400); + plotter->setMaximumSize(600, 400); + plotter->setToolbarEnabled(false); + plotter->clearAllMouseWheelActions(); + plotter->clearAllRegisteredMouseDoubleClickActions(); + plotter->clearAllRegisteredMouseDragActions(); + plotter->getPlotter()->setUseAntiAliasingForGraphs(false); + plotter->getPlotter()->setUseAntiAliasingForSystem(false); + plotter->getPlotter()->setUseAntiAliasingForText(false); + plotter->getPlotter()->setPlotLabel(QString("Setpoint Follow %1 Temperature").arg(refTempType)); + plotter->addGraph(graph1); + plotter->addGraph(graph2); + plotter->zoomToFit(); + plotter->setPlotUpdateEnabled(true); + plotter->redrawPlot(); + + mainVLayout->addWidget(plotter); mainVLayout->addStretch(); } @@ -850,40 +903,54 @@ FollowGroundTempSPMView::FollowGroundTempSPMView(const model::SetpointManagerFol new QLabel(QString("Supply temperature follows the Ground Temperature with an offset of %2 C.").arg(QString::number(offset))); mainVLayout->addWidget(followTempSPMlabel); - auto* series = new QLineSeries; - series->setName("Setpoint Temperature"); - auto* seriesOA = new QLineSeries; - seriesOA->setName("Ground Temperature"); - QRgb color1 = qRgb(255, 0, 0); - QPen pen1(color1); - pen1.setStyle(Qt::DotLine); - pen1.setWidth(1); - seriesOA->setPen(pen1); + // Create a JKQTPlotter widget + JKQTPlotter* plotter = new JKQTPlotter(); + plotter->setPlotUpdateEnabled(false); + JKQTPDatastore* ds = plotter->getDatastore(); + + // Generate the data for the plot + QVector x, y, yGround; std::vector xVals{-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40}; - for (const auto& x : xVals) { - double y = std::clamp(x + offset, minVal, maxVal); - series->append(x, y); - seriesOA->append(x, x); + for (const auto& xVal : xVals) { + x.append(xVal); + y.append(std::clamp(xVal + offset, minVal, maxVal)); + yGround.append(xVal); } - auto* chart = new QChart; - chart->legend()->hide(); - chart->addSeries(series); - chart->addSeries(seriesOA); - chart->createDefaultAxes(); - auto* xAxis = chart->axes(Qt::Horizontal)[0]; - xAxis->setTitleText("Ground Temperature [C]"); - auto* yAxis = chart->axes(Qt::Vertical)[0]; - yAxis->setTitleText("Setpoint Temperature [C]"); - - chart->setTitle("Setpoint Follow Ground Temperature"); - chart->setAnimationOptions(QChart::SeriesAnimations); - - auto* m_defaultChartView = new QChartView(chart, this); - m_defaultChartView->setRenderHint(QPainter::Antialiasing); - m_defaultChartView->setMinimumSize(400, 400); - mainVLayout->addWidget(m_defaultChartView); + // Add data to the datastore + size_t columnX = ds->addCopiedColumn(x, "x"); + size_t columnY = ds->addCopiedColumn(y, "y"); + size_t columnYGround = ds->addCopiedColumn(yGround, "yGround"); + + JKQTPXYLineGraph* graph1 = new JKQTPXYLineGraph(plotter); + graph1->setXColumn(columnX); + graph1->setYColumn(columnY); + graph1->setTitle("Setpoint Follow Ground Temperature"); + JKQTPXYLineGraph* graph2 = new JKQTPXYLineGraph(plotter); + graph2->setXColumn(columnX); + graph2->setYColumn(columnYGround); + graph2->setTitle("Setpoint Follow Ground Temperature"); + + plotter->getXAxis()->setAxisLabel(QString("Ground Temperature [C]")); + plotter->getYAxis()->setAxisLabel("Setpoint Temperature [C]"); + plotter->setMinimumSize(400, 400); + plotter->setMaximumSize(600, 400); + plotter->setToolbarEnabled(false); + plotter->clearAllMouseWheelActions(); + plotter->clearAllRegisteredMouseDoubleClickActions(); + plotter->clearAllRegisteredMouseDragActions(); + plotter->getPlotter()->setUseAntiAliasingForGraphs(false); + plotter->getPlotter()->setUseAntiAliasingForSystem(false); + plotter->getPlotter()->setUseAntiAliasingForText(false); + plotter->getPlotter()->setPlotLabel("Setpoint Follow Ground Temperature"); + plotter->addGraph(graph1); + plotter->addGraph(graph2); + plotter->zoomToFit(); + plotter->setPlotUpdateEnabled(true); + plotter->redrawPlot(); + + mainVLayout->addWidget(plotter); mainVLayout->addStretch(); }