diff --git a/examples/2d/CMakeLists.txt b/examples/2d/CMakeLists.txt new file mode 100644 index 0000000..b2f1424 --- /dev/null +++ b/examples/2d/CMakeLists.txt @@ -0,0 +1,28 @@ +set(target_name 2d) + +# Meta-Objects +set(${target_name}_MOC_HDRS mainwindow.h) +qt6_wrap_cpp(${target_name}_MOC_SRCS ${${target_name}_MOC_HDRS}) + +# Add executable target(s) +add_executable(${target_name} main.cpp mainwindow.ui ${${target_name}_MOC_SRCS} + mainwindow_funcs.cpp) + +# Set project-local include directories for target +target_include_directories( + ${target_name} + PRIVATE ${PROJECT_SOURCE_DIR}/src + ${PROJECT_BINARY_DIR}/src + ${PROJECT_BINARY_DIR}/examples/${target_name} + ${PROJECT_SOURCE_DIR}/examples/${target_name} + ${Qt6Core_INCLUDE_DIRS} + ${Qt6Gui_INCLUDE_DIRS} + ${Qt6OpenGL_INCLUDE_DIRS} + ${Qt6Widgets_INCLUDE_DIRS}) + +target_link_libraries(${target_name} PRIVATE # External libs + mildred) + +set_target_properties(${target_name} PROPERTIES RUNTIME ${target_name}) + +install(TARGETS ${target_name} RUNTIME) diff --git a/examples/2d/main.cpp b/examples/2d/main.cpp new file mode 100644 index 0000000..4ea52a6 --- /dev/null +++ b/examples/2d/main.cpp @@ -0,0 +1,12 @@ +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow mainWindow; + + mainWindow.show(); + return app.exec(); +} diff --git a/examples/2d/mainwindow.h b/examples/2d/mainwindow.h new file mode 100644 index 0000000..d3df298 --- /dev/null +++ b/examples/2d/mainwindow.h @@ -0,0 +1,43 @@ +#pragma once + +#include "entities/data2d.h" +#include "ui_mainwindow.h" + +class MainWindow : public QMainWindow +{ + Q_OBJECT + + public: + MainWindow(); + ~MainWindow() = default; + + /* + * UI + */ + + private: + // Main form declaration + Ui::MainWindow ui_; + + /* + * Data + */ + private: + // Data limits + double dataMin_{-5.0}, dataMax_{5.0}; + // Data granularity + int nPoints_{1000}; + // Test data + std::vector x_, y_, values_; + // Entity for data + Mildred::Data2DEntity *dataEntity_{nullptr}; + + public: + // Function Types + enum Test2DFunctions + { + AckleyFunction + }; + // Generate specified function + void generateFunction(Test2DFunctions function); +}; diff --git a/examples/2d/mainwindow.ui b/examples/2d/mainwindow.ui new file mode 100644 index 0000000..90eb174 --- /dev/null +++ b/examples/2d/mainwindow.ui @@ -0,0 +1,260 @@ + + + MainWindow + + + + 0 + 0 + 956 + 713 + + + + Basic Test + + + + + + + + 5 + 0 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + View + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Reset + + + + + + + Flat (2D) + + + + + + + Show scene bounding cuboid + + + + + + + + + + + 0 + 0 + + + + Axes + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Z + + + + + + + + 0 + 0 + + + + + + + + X + + + + + + + + 0 + 0 + + + + + + + + Y + + + + + + + + 0 + 0 + + + + + + + + Visible + + + + + + + Visible + + + + + + + Visible + + + + + + + + + + Mouse Coordinates + + + + + + + + Style + + + + + + + + + + + + External + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 0 + 0 + 956 + 22 + + + + + + + + Mildred::MildredWidget + QWidget +
widget.h
+ 1 +
+
+ + +
diff --git a/examples/2d/mainwindow_funcs.cpp b/examples/2d/mainwindow_funcs.cpp new file mode 100644 index 0000000..8c24668 --- /dev/null +++ b/examples/2d/mainwindow_funcs.cpp @@ -0,0 +1,51 @@ +#include "mainwindow.h" +#include "material.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow() : QMainWindow() +{ + ui_.setupUi(this); + + generateFunction(Test2DFunctions::AckleyFunction); + dataEntity_ = ui_.TestingWidget->addData2D("2D Function"); + dataEntity_->setData(x_, y_, values_); + + ui_.TestingWidget->zAxis()->setEnabled(true); + ui_.TestingWidget->zAxis()->setType(Mildred::AxisEntity::AxisType::Vertical); + //ui_.TestingWidget->yAxis()->setType(Mildred::AxisEntity::AxisType::Depth); + + ui_.TestingWidget->showAllData(); +}; + +// Generate specified function +void MainWindow::generateFunction(Test2DFunctions function) +{ + // Initialise the data and calculate the delta + // Data, all bounded to [-5,5] in x and y + const auto axisMin = -50.0, axisMax = 50.0, delta = (axisMax - axisMin) / (nPoints_ - 1); + + x_.reserve(nPoints_); + x_.clear(); + values_.reserve(nPoints_ * nPoints_); + values_.clear(); + + // Generate x axis and duplicate as y + for (auto n = 0; n <= nPoints_; ++n) + x_.push_back(n * delta); + y_ = x_; + + switch (function) + { + case (Test2DFunctions::AckleyFunction): + /* + * Ackley's Function + * f(x,y) = -20.0 * exp(-0.2 * sqrt(0.5 * (x^2 + y^2))) - exp(0.5 * (cos(2 * M_PI * x) + cos(2 * M_PI * y))) + e + + * 20 + */ + for (const auto x : x_) + for (const auto y : y_) + values_.push_back(-20.0 * exp(-0.2 * sqrt(0.5 * (x * x + y * y))) - + exp(0.5 * (cos(2 * M_PI * x) + cos(2 * M_PI * y))) + M_E + 20); + break; + } +} diff --git a/examples/3d/CMakeLists.txt b/examples/3d/CMakeLists.txt new file mode 100644 index 0000000..dd79073 --- /dev/null +++ b/examples/3d/CMakeLists.txt @@ -0,0 +1,28 @@ +set(target_name 3d) + +# Meta-Objects +set(${target_name}_MOC_HDRS mainwindow.h) +qt6_wrap_cpp(${target_name}_MOC_SRCS ${${target_name}_MOC_HDRS}) + +# Add executable target(s) +add_executable(${target_name} main.cpp mainwindow.ui ${${target_name}_MOC_SRCS} + mainwindow_funcs.cpp) + +# Set project-local include directories for target +target_include_directories( + ${target_name} + PRIVATE ${PROJECT_SOURCE_DIR}/src + ${PROJECT_BINARY_DIR}/src + ${PROJECT_BINARY_DIR}/examples/${target_name} + ${PROJECT_SOURCE_DIR}/examples/${target_name} + ${Qt6Core_INCLUDE_DIRS} + ${Qt6Gui_INCLUDE_DIRS} + ${Qt6OpenGL_INCLUDE_DIRS} + ${Qt6Widgets_INCLUDE_DIRS}) + +target_link_libraries(${target_name} PRIVATE # External libs + mildred) + +set_target_properties(${target_name} PROPERTIES RUNTIME ${target_name}) + +install(TARGETS ${target_name} RUNTIME) diff --git a/examples/3d/main.cpp b/examples/3d/main.cpp new file mode 100644 index 0000000..4ea52a6 --- /dev/null +++ b/examples/3d/main.cpp @@ -0,0 +1,12 @@ +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow mainWindow; + + mainWindow.show(); + return app.exec(); +} diff --git a/examples/3d/mainwindow.h b/examples/3d/mainwindow.h new file mode 100644 index 0000000..8fafa48 --- /dev/null +++ b/examples/3d/mainwindow.h @@ -0,0 +1,43 @@ +#pragma once + +#include "entities/data3d.h" +#include "ui_mainwindow.h" + +class MainWindow : public QMainWindow +{ + Q_OBJECT + + public: + MainWindow(); + ~MainWindow() = default; + + /* + * UI + */ + + private: + // Main form declaration + Ui::MainWindow ui_; + + /* + * Data + */ + private: + // Data limits + double dataMin_{-5.0}, dataMax_{5.0}; + // Data granularity + int nPoints_{1000}; + // Test data + std::vector x_, y_, z_, values_; + // Entity for data + Mildred::Data3DEntity *dataEntity_{nullptr}; + + public: + // Function Types + enum Test3DFunctions + { + AckleyFunction + }; + // Generate specified function + void generateFunction(Test3DFunctions function); +}; diff --git a/examples/3d/mainwindow.ui b/examples/3d/mainwindow.ui new file mode 100644 index 0000000..90eb174 --- /dev/null +++ b/examples/3d/mainwindow.ui @@ -0,0 +1,260 @@ + + + MainWindow + + + + 0 + 0 + 956 + 713 + + + + Basic Test + + + + + + + + 5 + 0 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + View + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Reset + + + + + + + Flat (2D) + + + + + + + Show scene bounding cuboid + + + + + + + + + + + 0 + 0 + + + + Axes + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Z + + + + + + + + 0 + 0 + + + + + + + + X + + + + + + + + 0 + 0 + + + + + + + + Y + + + + + + + + 0 + 0 + + + + + + + + Visible + + + + + + + Visible + + + + + + + Visible + + + + + + + + + + Mouse Coordinates + + + + + + + + Style + + + + + + + + + + + + External + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 0 + 0 + 956 + 22 + + + + + + + + Mildred::MildredWidget + QWidget +
widget.h
+ 1 +
+
+ + +
diff --git a/examples/3d/mainwindow_funcs.cpp b/examples/3d/mainwindow_funcs.cpp new file mode 100644 index 0000000..a3a03fb --- /dev/null +++ b/examples/3d/mainwindow_funcs.cpp @@ -0,0 +1,51 @@ +#include "mainwindow.h" +#include "material.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow() : QMainWindow() +{ + ui_.setupUi(this); + + generateFunction(Test3DFunctions::AckleyFunction); + dataEntity_ = ui_.TestingWidget->addData3D("3D Function"); + dataEntity_->setData(x_, y_, z_, values_); + + ui_.TestingWidget->zAxis()->setEnabled(true); + ui_.TestingWidget->zAxis()->setType(Mildred::AxisEntity::AxisType::Vertical); + //ui_.TestingWidget->yAxis()->setType(Mildred::AxisEntity::AxisType::Depth); + + ui_.TestingWidget->showAllData(); +}; + +// Generate specified function +void MainWindow::generateFunction(Test3DFunctions function) +{ + // Initialise the data and calculate the delta + // Data, all bounded to [-5,5] in x and y + const auto axisMin = -50.0, axisMax = 50.0, delta = (axisMax - axisMin) / (nPoints_ - 1); + + x_.reserve(nPoints_); + x_.clear(); + values_.reserve(nPoints_ * nPoints_); + values_.clear(); + + // Generate x axis and duplicate as y + for (auto n = 0; n <= nPoints_; ++n) + x_.push_back(n * delta); + y_ = x_; + + switch (function) + { + case (Test3DFunctions::AckleyFunction): + /* + * Ackley's Function + * f(x,y) = -20.0 * exp(-0.2 * sqrt(0.5 * (x^2 + y^2))) - exp(0.5 * (cos(2 * M_PI * x) + cos(2 * M_PI * y))) + e + + * 20 + */ + for (const auto x : x_) + for (const auto y : y_) + values_.push_back(-20.0 * exp(-0.2 * sqrt(0.5 * (x * x + y * y))) - + exp(0.5 * (cos(2 * M_PI * x) + cos(2 * M_PI * y))) + M_E + 20); + break; + } +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 09e1676..7198223 100755 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,3 +3,5 @@ add_subdirectory(groups) add_subdirectory(log-axes) add_subdirectory(errors) add_subdirectory(stress) +add_subdirectory(2d) +add_subdirectory(3d) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c51a8e7..a94a2a7 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,7 +30,7 @@ target_include_directories( target_link_libraries( mildred - PUBLIC ${WHOLE_ARCHIVE_FLAG} entities renderers1d classes + PUBLIC ${WHOLE_ARCHIVE_FLAG} entities renderers1d renderers2d renderers3d classes PRIVATE # External libs Qt6::Widgets Qt6::Core Qt6::3DCore Qt6::3DRender Qt6::3DExtras OpenGL::GL) diff --git a/src/entities/data2d.cpp b/src/entities/data2d.cpp index 83aac3f..8cf63d0 100644 --- a/src/entities/data2d.cpp +++ b/src/entities/data2d.cpp @@ -1,4 +1,5 @@ #include "entities/data2d.h" +#include "renderers/2d/stylefactory.h" using namespace Mildred; @@ -6,10 +7,14 @@ using namespace Mildred; /*! * Construct a new Data2DEntity storing a reference to the supplied @param metrics and with the given @param parent. */ -Data2DEntity::Data2DEntity(MildredMetrics &metrics, Qt3DCore::QNode *parent) : DataEntity(parent) {} - +Data2DEntity::Data2DEntity(const AxisEntity *xAxis, const AxisEntity* yAxis, const AxisEntity *valueAxis, Qt3DCore::QNode *parent, + StyleFactory2D::Style style) + : DataEntity(parent), xAxis_(xAxis), yAxis_(yAxis), valueAxis_(valueAxis), style_(style) +{ + dataRenderer_ = StyleFactory2D::createDataRenderer(style_, dataEntity_); +} /* - * Data + * Data */ //! Clear all data vectors @@ -31,9 +36,34 @@ void Data2DEntity::setData(std::vector x, std::vector y, std::ve { clearData(); - x_ = std::move(x); - y_ = std::move(y); - values_ = std::move(values); + if (x.size() * y.size() != values.size()) + printf("Irregular vector sizes provided (%zu (x) vs %zu (y) vs %zu (values)) so data will be ignored.\n", x.size(), y.size(), values.size()); + else + { + x_ = std::move(x); + y_ = std::move(y); + values_ = std::move(values); + } + + // Determine axis extrema + auto vit = values_.cbegin(); + for (const auto x : x_) + for (const auto y : y_) + { + updateExtrema(x, y, *vit); + ++vit; + } + + create(); +} - // create(); +/* + * Rendering + */ + +//! Create renderables in the current style +void Data2DEntity::create() +{ + assert(dataRenderer_); + dataRenderer_->create(colourDefinition(), x_, xAxis_, y_, yAxis_, values_, valueAxis_); } diff --git a/src/entities/data2d.h b/src/entities/data2d.h index d4652cf..f0a58d9 100644 --- a/src/entities/data2d.h +++ b/src/entities/data2d.h @@ -1,9 +1,12 @@ #pragma once #include "entities/data.h" +#include "renderers/2d/stylefactory.h" namespace Mildred { +// Forward Declarations +class AxisEntity; //! Data2DEntity encapsulates entities representing a 2-dimensional dataset. /*! * Data2DEntity provides a general class to contain and display a single two-dimensional dataset. @@ -13,10 +16,9 @@ namespace Mildred */ class Data2DEntity : public DataEntity { - Q_OBJECT - public: - Data2DEntity(MildredMetrics &metrics, Qt3DCore::QNode *parent = nullptr); + Data2DEntity(const AxisEntity *xAxis, const AxisEntity *yAxis, const AxisEntity *valueAxis, Qt3DCore::QNode *parent = nullptr, + StyleFactory2D::Style style = StyleFactory2D::Style::Line); ~Data2DEntity() = default; /* @@ -35,5 +37,22 @@ class Data2DEntity : public DataEntity void clearData(); // Set display data void setData(std::vector x, std::vector y, std::vector values); + + /* + * Rendering + */ + private: + // Axes to plot against + const AxisEntity *xAxis_{nullptr}, *yAxis_{nullptr}, *valueAxis_{nullptr}; + // Data style + StyleFactory2D::Style style_; + // Data Renderer + std::shared_ptr dataRenderer_{nullptr}; + // Orientation + AxisEntity::AxisType abscissa_{AxisEntity::AxisType::Horizontal}, ordinate_{AxisEntity::AxisType::Vertical}, applicate_{AxisEntity::AxisType::Depth}; + + protected: + // Create renderables from current data + void create() override; }; -} // namespace Mildred \ No newline at end of file +} // namespace Mildred diff --git a/src/entities/data3d.cpp b/src/entities/data3d.cpp index 2039a1e..103b4f5 100644 --- a/src/entities/data3d.cpp +++ b/src/entities/data3d.cpp @@ -1,4 +1,5 @@ #include "entities/data3d.h" +#include "renderers/3d/stylefactory.h" using namespace Mildred; @@ -6,10 +7,14 @@ using namespace Mildred; /*! * Construct a new Data3DEntity storing a reference to the supplied @param metrics and with the given @param parent. */ -Data3DEntity::Data3DEntity(MildredMetrics &metrics, Qt3DCore::QNode *parent) : DataEntity(parent) {} - +Data3DEntity::Data3DEntity(const AxisEntity *xAxis, const AxisEntity* yAxis, const AxisEntity* zAxis, const AxisEntity *valueAxis, Qt3DCore::QNode *parent, + StyleFactory3D::Style style) + : DataEntity(parent), xAxis_(xAxis), yAxis_(yAxis), zAxis_(zAxis), valueAxis_(valueAxis), style_(style) +{ + dataRenderer_ = StyleFactory3D::createDataRenderer(style_, dataEntity_); +} /* - * Data + * Data */ //! Clear all data vectors @@ -25,17 +30,42 @@ void Data3DEntity::clearData() //! Set display data /*! - * Set the supplied three-dimensional data (axis points @param x, @param y, and @param z and @param values at those points). The - * data are copied to local arrays and entities representing the data in the current style are immediately created. + * Set the supplied two-dimensional data (axis points @param x and @param y and @param z and @param values at those points). The data are + * copied to local arrays and entities representing the data in the current style are immediately created. */ void Data3DEntity::setData(std::vector x, std::vector y, std::vector z, std::vector values) { clearData(); - x_ = std::move(x); - y_ = std::move(y); - z_ = std::move(z); - values_ = std::move(values); + if (x.size() * y.size() * z.size()!= values.size()) + printf("Irregular vector sizes provided (%zu (x) vs %zu (y) vs %zu (z) vs %zu (values)) so data will be ignored.\n", x.size(), y.size(), z.size(), values.size()); + else + { + x_ = std::move(x); + y_ = std::move(y); + z_ = std::move(z); + values_ = std::move(values); + } + + // Determine axis extrema + auto vit = values_.cbegin(); + for (const auto x : x_) + for (const auto y : y_) + { + updateExtrema(x, y, *vit); + ++vit; + } + + create(); +} - // create(); +/* + * Rendering + */ + +//! Create renderables in the current style +void Data3DEntity::create() +{ + assert(dataRenderer_); + dataRenderer_->create(colourDefinition(), x_, xAxis_, y_, yAxis_, z_, zAxis_, values_, valueAxis_); } diff --git a/src/entities/data3d.h b/src/entities/data3d.h index ef76bba..8460073 100644 --- a/src/entities/data3d.h +++ b/src/entities/data3d.h @@ -1,12 +1,13 @@ #pragma once #include "entities/data.h" +#include "renderers/3d/stylefactory.h" namespace Mildred { -//! Data2DEntity encapsulates entities representing a 3-dimensional dataset. +//! Data3DEntity encapsulates entities representing a 3-dimensional dataset. /*! - * Data2DEntity provides a general class to contain and display a single two-dimensional dataset. + * Data3DEntity provides a general class to contain and display a single two-dimensional dataset. * * Data passed to the class in the form of four std::vector containing x, y, and z axis points and values. The vector * sizes of the axis values provided determines the expected size of the value points vector. @@ -33,5 +34,22 @@ class Data3DEntity : public DataEntity void clearData(); // Set display data void setData(std::vector x, std::vector y, std::vector z, std::vector values); + + /* + * Rendering + */ + private: + // Axes to plot against + const AxisEntity *xAxis_{nullptr}, *yAxis_{nullptr}, *zAxis_{nullptr}, *valueAxis_{nullptr}; + // Data style + StyleFactory3D::Style style_; + // Data Renderer + std::shared_ptr dataRenderer_{nullptr}; + // Orientation + AxisEntity::AxisType abscissa_{AxisEntity::AxisType::Horizontal}, ordinate_{AxisEntity::AxisType::Vertical}, applicate_{AxisEntity::AxisType::Depth}; + + protected: + // Create renderables from current data + void create() override; }; -} // namespace Mildred \ No newline at end of file +} // namespace Mildred diff --git a/src/renderers/2d/CMakeLists.txt b/src/renderers/2d/CMakeLists.txt new file mode 100644 index 0000000..950d704 --- /dev/null +++ b/src/renderers/2d/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library( + renderers2d + line.cpp + stylefactory.cpp + base.h + line.h + stylefactory.h) + +target_include_directories( + renderers2d + PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src + ${Qt63DCore_INCLUDE_DIRS} ${Qt63DExtras_INCLUDE_DIRS} + ${Qt63DRender_INCLUDE_DIRS}) diff --git a/src/renderers/2d/base.h b/src/renderers/2d/base.h new file mode 100644 index 0000000..ec2f140 --- /dev/null +++ b/src/renderers/2d/base.h @@ -0,0 +1,36 @@ +#pragma once + +#include "entities/data.h" + +namespace Mildred +{ +//! DataRenderer2DBase is the base class for all 2-dimensional data renderers. +/*! + * DataRenderer2DBase provides a base class for all 2-dimensional data rendering styles. + */ +class DataRenderer2D +{ + public: + DataRenderer2D(Qt3DCore::QEntity *rootEntity) : rootEntity_(rootEntity){}; + virtual ~DataRenderer2D() = default; + + /* + * Entities + */ + protected: + // Root entity + Qt3DCore::QEntity *rootEntity_{nullptr}; + + /* + * Rendering + */ + protected: + // Colour definition + ColourDefinition colour_; + + public: + // Create entities from the supplied axes and data + virtual void create(const ColourDefinition &colour, const std::vector &x, const AxisEntity *xAxis, + const std::vector &y, const AxisEntity *yAxis, const std::vector &values, const AxisEntity *valueAxis) = 0; +}; +} diff --git a/src/renderers/2d/line.cpp b/src/renderers/2d/line.cpp new file mode 100644 index 0000000..5387388 --- /dev/null +++ b/src/renderers/2d/line.cpp @@ -0,0 +1,68 @@ +#include "renderers/2d/line.h" + +using namespace Mildred; + +LineRenderer2D::LineRenderer2D(Qt3DCore::QEntity *rootEntity) : DataRenderer2D(rootEntity) +{ + lines_ = new LineEntity(rootEntity_); +} + +LineRenderer2D::~LineRenderer2D() +{ + // for (auto &line : lines_) + // line->setParent(static_cast(nullptr)); + if (lines_) + lines_->setParent(static_cast(nullptr)); +}; + +/* + * Rendering + */ + +// Create entities from the supplied metrics and data +void LineRenderer2D::create(const ColourDefinition &colour, const std::vector &x, const AxisEntity *xAxis, + const std::vector &y, const AxisEntity *yAxis, const std::vector &values, const AxisEntity *valueAxis) +{ + assert(lines_); + lines_->clear(); + // for (auto &line : lines_) + // { + // assert(line); + // line->clear(); + // } + // lines_->clear(); + // return; + colour_ = colour; + + // Loop over data and add vertices + auto xit = x.cbegin(), yit = y.cbegin(), vit = values.cbegin(); + // printf("%d %d\n", x.size(), lines_.size()); + + // int x_ = x.size(); + // lines_.resize(1); + // LineEntity* line = new LineEntity(rootEntity_); + // line->addVertex({50, 50, 0}, colour_.colour(50)); + // line->setBasicIndices(); + // line->finalise(); + // lines_.emplace_back(line); + // lines_.resize(x_); + while (xit != x.end()) + { + lines_->addVertex(xAxis->toScaled(*xit) + yAxis->toScaled(*yit) + valueAxis->toScaled(*vit), colour_.colour(*vit)); + // LineEntity* line = new LineEntity(rootEntity_); + // line->addVertex(xAxis->toScaled(*xit) + yAxis->toScaled(*yit), colour_.colour(*vit)); + ++xit; + ++yit; + ++vit; + // line->setBasicIndices(); + // line->finalise(); + // lines_.emplace_back(line); + } + + // printf("%d\n", lines_.size()); + // Set basic indices + lines_->setBasicIndices(); + + // Finalise the entity + lines_->finalise(); +} diff --git a/src/renderers/2d/line.h b/src/renderers/2d/line.h new file mode 100644 index 0000000..54224e6 --- /dev/null +++ b/src/renderers/2d/line.h @@ -0,0 +1,31 @@ +#pragma once + +#include "entities/line.h" +#include "renderers/2d/base.h" + +namespace Mildred +{ +//! LineRenderer1D renders 2D data as a line. +/*! + * LineRenderer2D manages the creation of entities for displaying 2D data as a simple line. + */ +class LineRenderer2D : public DataRenderer2D +{ + public: + LineRenderer2D(Qt3DCore::QEntity *rootEntity); + ~LineRenderer2D(); + + /* + * Rendering + */ + private: + // Line entity + LineEntity *lines_{nullptr}; + // std::vector lines_; + + public: + // Create entities from the supplied metrics and data + void create(const ColourDefinition &colour, const std::vector &x, const AxisEntity *xAxis, + const std::vector &y, const AxisEntity *yAxis, const std::vector &values, const AxisEntity *valueAxis); +}; +} // namespace Mildred diff --git a/src/renderers/2d/stylefactory.cpp b/src/renderers/2d/stylefactory.cpp new file mode 100644 index 0000000..29e8a06 --- /dev/null +++ b/src/renderers/2d/stylefactory.cpp @@ -0,0 +1,15 @@ +#include "renderers/2d/stylefactory.h" +#include "renderers/2d/line.h" + +namespace Mildred +{ +namespace StyleFactory2D +{ +// Produce renderer for the specified style +std::shared_ptr createDataRenderer(Style style, Qt3DCore::QEntity *rootEntity) +{ + if (style == Style::Line) + return std::make_shared(rootEntity); +} +} // namespace StyleFactory2D +} // namespace Mildred diff --git a/src/renderers/2d/stylefactory.h b/src/renderers/2d/stylefactory.h new file mode 100644 index 0000000..a8d397b --- /dev/null +++ b/src/renderers/2d/stylefactory.h @@ -0,0 +1,25 @@ +#pragma once + +#include "renderers/2d/base.h" + +namespace Mildred +{ +//! StyleFactory2D provides access to 2-dimensional data renderers. +/*! + * StyleFactory2D creates 2D renderer objects on demand which can then be used by a parent entity in order to provide data + * display. + */ +namespace StyleFactory2D +{ +// Styles for 2-dimensional data rendering +enum class Style +{ + None, + Line +}; + +// Produce renderer for the specified style +std::shared_ptr createDataRenderer(Style style, Qt3DCore::QEntity *rootEntity); + +} // namespace StyleFactory2D +} // namespace Mildred diff --git a/src/renderers/3d/CMakeLists.txt b/src/renderers/3d/CMakeLists.txt new file mode 100644 index 0000000..39a00b2 --- /dev/null +++ b/src/renderers/3d/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library( + renderers3d + line.cpp + stylefactory.cpp + base.h + line.h + stylefactory.h) + +target_include_directories( + renderers3d + PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src + ${Qt63DCore_INCLUDE_DIRS} ${Qt63DExtras_INCLUDE_DIRS} + ${Qt63DRender_INCLUDE_DIRS}) diff --git a/src/renderers/3d/base.h b/src/renderers/3d/base.h new file mode 100644 index 0000000..907e161 --- /dev/null +++ b/src/renderers/3d/base.h @@ -0,0 +1,36 @@ +#pragma once + +#include "entities/data.h" + +namespace Mildred +{ +//! DataRenderer3DBase is the base class for all 3-dimensional data renderers. +/*! + * DataRenderer3DBase provides a base class for all 3-dimensional data rendering styles. + */ +class DataRenderer3D +{ + public: + DataRenderer3D(Qt3DCore::QEntity *rootEntity) : rootEntity_(rootEntity){}; + virtual ~DataRenderer3D() = default; + + /* + * Entities + */ + protected: + // Root entity + Qt3DCore::QEntity *rootEntity_{nullptr}; + + /* + * Rendering + */ + protected: + // Colour definition + ColourDefinition colour_; + + public: + // Create entities from the supplied axes and data + virtual void create(const ColourDefinition &colour, const std::vector &x, const AxisEntity *xAxis, + const std::vector &y, const AxisEntity *yAxis, const std::vector &values, const AxisEntity *valueAxis) = 0; +}; +} diff --git a/src/renderers/3d/contours.cpp b/src/renderers/3d/contours.cpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/renderers/3d/contours.cpp @@ -0,0 +1 @@ + diff --git a/src/renderers/3d/contours.h b/src/renderers/3d/contours.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/renderers/3d/contours.h @@ -0,0 +1 @@ + diff --git a/src/renderers/3d/line.cpp b/src/renderers/3d/line.cpp new file mode 100644 index 0000000..19e5c2e --- /dev/null +++ b/src/renderers/3d/line.cpp @@ -0,0 +1,68 @@ +#include "renderers/3d/line.h" + +using namespace Mildred; + +LineRenderer3D::LineRenderer3D(Qt3DCore::QEntity *rootEntity) : DataRenderer3D(rootEntity) +{ + lines_ = new LineEntity(rootEntity_); +} + +LineRenderer3D::~LineRenderer3D() +{ + // for (auto &line : lines_) + // line->setParent(static_cast(nullptr)); + if (lines_) + lines_->setParent(static_cast(nullptr)); +}; + +/* + * Rendering + */ + +// Create entities from the supplied metrics and data +void LineRenderer3D::create(const ColourDefinition &colour, const std::vector &x, const AxisEntity *xAxis, + const std::vector &y, const AxisEntity *yAxis, const std::vector &values, const AxisEntity *valueAxis) +{ + assert(lines_); + lines_->clear(); + // for (auto &line : lines_) + // { + // assert(line); + // line->clear(); + // } + // lines_->clear(); + // return; + colour_ = colour; + + // Loop over data and add vertices + auto xit = x.cbegin(), yit = y.cbegin(), vit = values.cbegin(); + // printf("%d %d\n", x.size(), lines_.size()); + + // int x_ = x.size(); + // lines_.resize(1); + // LineEntity* line = new LineEntity(rootEntity_); + // line->addVertex({50, 50, 0}, colour_.colour(50)); + // line->setBasicIndices(); + // line->finalise(); + // lines_.emplace_back(line); + // lines_.resize(x_); + while (xit != x.end()) + { + lines_->addVertex(xAxis->toScaled(*xit) + yAxis->toScaled(*yit) + valueAxis->toScaled(*vit), colour_.colour(*vit)); + // LineEntity* line = new LineEntity(rootEntity_); + // line->addVertex(xAxis->toScaled(*xit) + yAxis->toScaled(*yit), colour_.colour(*vit)); + ++xit; + ++yit; + ++vit; + // line->setBasicIndices(); + // line->finalise(); + // lines_.emplace_back(line); + } + + // printf("%d\n", lines_.size()); + // Set basic indices + lines_->setBasicIndices(); + + // Finalise the entity + lines_->finalise(); +} diff --git a/src/renderers/3d/line.h b/src/renderers/3d/line.h new file mode 100644 index 0000000..970c489 --- /dev/null +++ b/src/renderers/3d/line.h @@ -0,0 +1,31 @@ +#pragma once + +#include "entities/line.h" +#include "renderers/3d/base.h" + +namespace Mildred +{ +//! LineRenderer3D renders 3D data as a line. +/*! + * LineRenderer3D manages the creation of entities for displaying 3D data as a simple line. + */ +class LineRenderer3D : public DataRenderer3D +{ + public: + LineRenderer3D(Qt3DCore::QEntity *rootEntity); + ~LineRenderer3D(); + + /* + * Rendering + */ + private: + // Line entity + LineEntity *lines_{nullptr}; + // std::vector lines_; + + public: + // Create entities from the supplied metrics and data + void create(const ColourDefinition &colour, const std::vector &x, const AxisEntity *xAxis, + const std::vector &y, const AxisEntity *yAxis, const std::vector &values, const AxisEntity *valueAxis); +}; +} // namespace Mildred diff --git a/src/renderers/3d/stylefactory.cpp b/src/renderers/3d/stylefactory.cpp new file mode 100644 index 0000000..a840513 --- /dev/null +++ b/src/renderers/3d/stylefactory.cpp @@ -0,0 +1,15 @@ +#include "renderers/3d/stylefactory.h" +#include "renderers/3d/line.h" + +namespace Mildred +{ +namespace StyleFactory3D +{ +// Produce renderer for the specified style +std::shared_ptr createDataRenderer(Style style, Qt3DCore::QEntity *rootEntity) +{ + if (style == Style::Line) + return std::make_shared(rootEntity); +} +} // namespace StyleFactory3D +} // namespace Mildred diff --git a/src/renderers/3d/stylefactory.h b/src/renderers/3d/stylefactory.h new file mode 100644 index 0000000..6024867 --- /dev/null +++ b/src/renderers/3d/stylefactory.h @@ -0,0 +1,25 @@ +#pragma once + +#include "renderers/3d/base.h" + +namespace Mildred +{ +//! StyleFactory3D provides access to 3-dimensional data renderers. +/*! + * StyleFactory3D creates 3D renderer objects on demand which can then be used by a parent entity in order to provide data + * display. + */ +namespace StyleFactory3D +{ +// Styles for 3-dimensional data rendering +enum class Style +{ + None, + Line +}; + +// Produce renderer for the specified style +std::shared_ptr createDataRenderer(Style style, Qt3DCore::QEntity *rootEntity); + +} // namespace StyleFactory3D +} // namespace Mildred diff --git a/src/renderers/CMakeLists.txt b/src/renderers/CMakeLists.txt index dfe4b96..642e957 100755 --- a/src/renderers/CMakeLists.txt +++ b/src/renderers/CMakeLists.txt @@ -1 +1,3 @@ add_subdirectory(1d) +add_subdirectory(2d) +add_subdirectory(3d) diff --git a/src/widget.cpp b/src/widget.cpp index bde20f9..d1f620f 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -204,6 +204,56 @@ Data1DEntity *MildredWidget::addData1D(std::string_view tag) return entity; } +// Add new 2-dimensinal data entity for supplied data +Data2DEntity *MildredWidget::addData2D(std::string_view tag) +{ + // Check for existing tag + auto it = std::find_if(dataEntities_.begin(), dataEntities_.end(), [tag](const auto &d) { return tag == d.first; }); + if (it != dataEntities_.end()) + { + printf("Data with tag '%s' already exists, so can't add it again.\n", it->first.c_str()); + throw(std::runtime_error("Duplicate DataEntity tag created.\n")); + } + + // Create a new entity + auto *entity = new Data2DEntity(xAxis_, yAxis_, zAxis_, dataEntityParent_); + connect(&metrics_, SIGNAL(metricsChanged()), entity, SLOT(updateRenderables())); + dataEntities_.emplace_back(tag, entity); + + // Add a material + auto *material = createMaterial(entity, RenderableMaterial::VertexShaderType::ClippedToDataVolume, + RenderableMaterial::GeometryShaderType::LineTesselator, + RenderableMaterial::FragmentShaderType::PerVertexPhong); + entity->setDataMaterial(material); + + return entity; +} + +// Add new 3-dimensinal data entity for supplied data +Data3DEntity *MildredWidget::addData3D(std::string_view tag) +{ + // Check for existing tag + auto it = std::find_if(dataEntities_.begin(), dataEntities_.end(), [tag](const auto &d) { return tag == d.first; }); + if (it != dataEntities_.end()) + { + printf("Data with tag '%s' already exists, so can't add it again.\n", it->first.c_str()); + throw(std::runtime_error("Duplicate DataEntity tag created.\n")); + } + + // Create a new entity + auto *entity = new Data3DEntity(xAxis_, yAxis_, zAxis_, dataEntityParent_); + connect(&metrics_, SIGNAL(metricsChanged()), entity, SLOT(updateRenderables())); + dataEntities_.emplace_back(tag, entity); + + // Add a material + auto *material = createMaterial(entity, RenderableMaterial::VertexShaderType::ClippedToDataVolume, + RenderableMaterial::GeometryShaderType::LineTesselator, + RenderableMaterial::FragmentShaderType::PerVertexPhong); + entity->setDataMaterial(material); + + return entity; +} + /* * Grouping */ @@ -214,4 +264,4 @@ DisplayGroup *MildredWidget::addDisplayGroup() auto newGroup = displayGroups_.emplace_back(std::make_shared()); return newGroup.get(); -} \ No newline at end of file +} diff --git a/src/widget.h b/src/widget.h index 07b1d22..38cbd63 100644 --- a/src/widget.h +++ b/src/widget.h @@ -4,6 +4,8 @@ #include "displaygroup.h" #include "entities/axis.h" #include "entities/data1d.h" +#include "entities/data2d.h" +#include "entities/data3d.h" #include "framegraph.h" #include "material.h" #include @@ -206,6 +208,8 @@ class MildredWidget : public QWidget public: // Add new data entity for supplied data Data1DEntity *addData1D(std::string_view tag); + Data2DEntity *addData2D(std::string_view tag); + Data3DEntity *addData3D(std::string_view tag); /* * Grouping @@ -218,4 +222,4 @@ class MildredWidget : public QWidget // Create new display group DisplayGroup *addDisplayGroup(); }; -} // namespace Mildred \ No newline at end of file +} // namespace Mildred