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();
}