feat: technique overhaul

This commit is contained in:
Djairo Hougee 2024-05-26 14:21:06 +02:00
parent 211a219431
commit 86ec78f831
16 changed files with 222 additions and 144 deletions

View File

@ -54,6 +54,8 @@ add_executable(ParticleTrackTrace MACOSX_BUNDLE main.cpp
layers/Layer.h layers/Layer.h
layers/LGlyphLayer.cpp layers/LGlyphLayer.cpp
layers/LGlyphLayer.h layers/LGlyphLayer.h
layers/Technique.cpp
layers/Technique.h
Program.cpp Program.cpp
Program.h Program.h
commands/TimerCallbackCommand.h commands/TimerCallbackCommand.h

View File

@ -1,3 +1,4 @@
#include <stdexcept>
#include <vtkRenderWindow.h> #include <vtkRenderWindow.h>
#include <vtkPointData.h> #include <vtkPointData.h>
#include <vtkDoubleArray.h> #include <vtkDoubleArray.h>
@ -53,11 +54,10 @@ void Program::setupCameraCallback() {
Program::Program(QWidget *parent): QVTKOpenGLNativeWidget(parent) { Program::Program(QWidget *parent): QVTKOpenGLNativeWidget(parent) {
this->win = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New(); this->win = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
// this->interact = vtkSmartPointer<vtkRenderWindowInteractor>::New();
// this->interact = vtkSmartPointer<QVTKInteractor>::New();
setRenderWindow(this->win); setRenderWindow(this->win);
this->interact = win->GetInteractor(); this->interact = win->GetInteractor();
this->cam = createNormalisedCamera(); this->cam = createNormalisedCamera();
this->activeIdx = -1;
this->win->SetNumberOfLayers(0); this->win->SetNumberOfLayers(0);
setWinProperties(); setWinProperties();
@ -66,44 +66,55 @@ Program::Program(QWidget *parent): QVTKOpenGLNativeWidget(parent) {
} }
void Program::addLayer(Layer *layer) { void Program::addTechnique(Technique *technique) {
layer->setCamera(this->cam); this->techniques.push_back(technique);
this->layers.push_back(layer);
this->win->AddRenderer(layer->getLayer());
this->win->SetNumberOfLayers(this->win->GetNumberOfLayers() + 1);
} }
void Program::removeLayer(Layer *layer) { void Program::removeTechnique(Technique *technique) {
this->win->RemoveRenderer(layer->getLayer()); auto it = std::find(this->techniques.begin(), this->techniques.end(), technique);
if (it != this->techniques.end()) {
auto it = std::find(this->layers.begin(), this->layers.end(), layer); int idx = it - this->techniques.begin();
if (it != this->layers.end()) { if (idx == this->activeIdx) {
this->layers.erase(it); throw std::out_of_range("Can't remove active technique.");
this->win->SetNumberOfLayers(this->win->GetNumberOfLayers() - 1); }
this->techniques.erase(it);
this->activeIdx = -1;
setActiveTechnique(0);
} }
} }
void Program::updateData(int t) { void Program::updateData(int t) {
// FIXME: think on how to update techniques; do we update all? just active? unsure.
win->Render(); win->Render();
for (Layer *l: layers) { this->techniques[this->activeIdx]->updateData(t);
l->updateData(t);
}
} }
void Program::setupInteractions() { void Program::setActiveTechnique(int idx) {
for (Layer *l: layers) { // Only change things if a different technique has been selected.
l->addObservers(this->interact); if (idx == this->activeIdx) {
return;
} }
// check the given idx is valid.
if (idx >= this->techniques.size()) {
throw std::out_of_range("Index out of range!");
}
if (this->activeIdx >= 0 and this->activeIdx < this->techniques.size())
this->techniques[this->activeIdx]->unbind(this->win, this->interact);
this->techniques[idx]->bind(this->win, this->interact);
this->activeIdx = idx;
} }
void Program::render() {
setupInteractions();
win->Render();
interact->Start();
}
Program::~Program() { Program::~Program() {
cout << "deleting program" << endl; cout << "deleting program" << endl;
} }
vtkSmartPointer<vtkCamera> Program::getCamera() {
return this->cam;
}

View File

@ -7,6 +7,7 @@
#include <vtkRenderer.h> #include <vtkRenderer.h>
#include "layers/Layer.h" #include "layers/Layer.h"
#include "layers/Technique.h"
/** This class manages the upper levels of the vtk pipeline; it has attributes for the vtkrenderWindow and a vector of Layers to represent a variable number of vtkRenderers. /** This class manages the upper levels of the vtk pipeline; it has attributes for the vtkrenderWindow and a vector of Layers to represent a variable number of vtkRenderers.
* It can also set up a vtkTimer by connecting an instance of TimerCallbackCommand with its contained vtkRenderWindowInteractor. * It can also set up a vtkTimer by connecting an instance of TimerCallbackCommand with its contained vtkRenderWindowInteractor.
@ -15,19 +16,19 @@ class Program : public QVTKOpenGLNativeWidget {
Q_OBJECT Q_OBJECT
private: private:
/** This attribute models a variable number of vtkRenderers, managed through the abstract Layer class. /** This attribute models a variable number of vtkRenderers, managed through the abstract Technique class.
*/ */
std::vector<Layer *> layers; std::vector<Technique *> techniques;
int activeIdx;
/** The window this program's layers render to. /** The window this program's layers render to.
*/ */
// vtkSmartPointer<vtkRenderWindow> win;
vtkSmartPointer<vtkGenericOpenGLRenderWindow> win; vtkSmartPointer<vtkGenericOpenGLRenderWindow> win;
/** The interactor through which the layers can interact with the window. /** The interactor through which the layers can interact with the window.
*/ */
vtkSmartPointer<vtkRenderWindowInteractor> interact; vtkSmartPointer<vtkRenderWindowInteractor> interact;
// vtkSmartPointer<QVTKInteractor> interact;
/** The camera used by all layers for this program. /** The camera used by all layers for this program.
@ -53,33 +54,30 @@ public:
Program(QWidget *parent = nullptr); Program(QWidget *parent = nullptr);
~Program() override; ~Program() override;
/** This function adds a new layer (and thus vtkRenderer) to the program. /** This function adds a new technique to the program.
* The layer is expected to set its own position in the vtkRenderWindow layer system. * The technique is expected to manage the layers itself in the vtkRenderWindow layer system.
* @param layer : pointer to the layer to add. * @param technique : pointer to the technique to add.
*/ */
void addLayer(Layer *layer); void addTechnique(Technique *technique);
/** This function removes a given layer from the vtkRenderWindow and layers vector. /** This function removes a given layer from the vtkRenderWindow and layers vector.
* If the given layer is not actually in the program, nothing happens. * If the given layer is not actually in the program, nothing happens.
* @param layer : the layer to removeLayer * @param layer : the layer to removeTechnique
*/ */
void removeLayer(Layer *layer); void removeTechnique(Technique *layer);
/** This function updates the data for the associated layers to the given timestamp. /** This function updates the data for the associated techniques to the given timestamp.
* Also updates the renderWindow. * Also updates the renderWindow.
* @param t : the timestamp to update the data to. * @param t : the timestamp to update the data to.
*/ */
void updateData(int t); void updateData(int t);
/** This function adds all interactors of each layer to the interactor/window
*/
void setupInteractions();
/** // TODO: using an idx to indicate which technique to use is not ideal; use an enum instead? But then the question is where to put it...
* This function renders the vtkRenderWindow for the first time. void setActiveTechnique(int idx);
* Only call this function once!
*/
void render(); vtkSmartPointer<vtkCamera> getCamera();
}; };

View File

@ -22,28 +22,7 @@ MainWindow::MainWindow(QWidget* parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
this->setupTechniques();
cout << "Reading data..." << endl;
string dataPath = "../../../../data";
shared_ptr<UVGrid> uvGrid = make_shared<UVGrid>(dataPath);
auto kernelRK4 = make_unique<RK4AdvectionKernel>(uvGrid);
auto kernelRK4BoundaryChecked = make_unique<SnapBoundaryConditionKernel>(std::move(kernelRK4), uvGrid);
cout << "Starting vtk..." << endl;
auto l = new LGlyphLayer(uvGrid, std::move(kernelRK4BoundaryChecked));
// l->spoofPoints();
l->setDt(3600);
// TODO: implement feature to call this function on widget
// l->cycleGlyphStyle();
Program *program = this->ui->program;
program->addLayer(new BackgroundImage(dataPath + "/map_qgis_1035.png"));
// TODO: implement feature to cycle between layers thru QT
program->addLayer(new EGlyphLayer(uvGrid));
program->addLayer(new EColLayer(uvGrid));
program->addLayer(l);
program->setupInteractions();
} }
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
@ -51,6 +30,50 @@ MainWindow::~MainWindow() {
} }
void MainWindow::setupTechniques() {
cout << "Reading data..." << endl;
string dataPath = "../../../../data";
shared_ptr<UVGrid> uvGrid = make_shared<UVGrid>(dataPath);
// initialize techniques
Program *program = this->ui->program;
auto technique1 = new Technique(program->getCamera());
auto technique2 = new Technique(program->getCamera());
// add bg layer
auto bg = new BackgroundImage(dataPath + "/map_qgis_1035.png");
technique1->addLayer(bg);
technique2->addLayer(bg);
// add Euler layers
technique1->addLayer(new EColLayer(uvGrid));
technique2->addLayer(new EGlyphLayer(uvGrid));
// setup LGlyphLayer
auto kernelRK4 = make_unique<RK4AdvectionKernel>(uvGrid);
auto kernelRK4BoundaryChecked = make_unique<SnapBoundaryConditionKernel>(std::move(kernelRK4), uvGrid);
auto lGlyph = new LGlyphLayer(uvGrid, std::move(kernelRK4BoundaryChecked));
lGlyph->setDt(3600);
technique1->addLayer(lGlyph);
// technique2->addLayer(new LColLayer(uvGrid)); // TODO: add LColLayer
technique2->addLayer(lGlyph);
cout << technique1->numberOfLayers() << endl;
program->addTechnique(technique1);
program->addTechnique(technique2);
program->setActiveTechnique(0);
// TODO: implement feature to call this function on widget
// l->spoofPoints();
// l->cycleGlyphStyle();
}
/* -------------------------------------------------------------------- /* --------------------------------------------------------------------
* + QTWidget callbacks + * + QTWidget callbacks +
* --------------------------------------------------------------------*/ * --------------------------------------------------------------------*/

View File

@ -2,6 +2,7 @@
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow> #include <QMainWindow>
#include "../advection/UVGrid.h"
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -32,6 +33,8 @@ private slots:
private: private:
Ui::MainWindow* ui; Ui::MainWindow* ui;
void setupTechniques();
}; };
#endif #endif

View File

@ -173,6 +173,10 @@ void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> intera
interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack); interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack);
} }
void LGlyphLayer::removeObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
// todo: logic for these
}
void LGlyphLayer::setDt(int dt) { void LGlyphLayer::setDt(int dt) {
this->dt = dt; this->dt = dt;

View File

@ -40,6 +40,7 @@ public:
vtkSmartPointer<SpawnPointCallback> createSpawnPointCallback(); vtkSmartPointer<SpawnPointCallback> createSpawnPointCallback();
void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override; void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override;
void removeObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override;
/** /**

View File

@ -21,7 +21,7 @@
#include "../CartographicTransformation.h" #include "../CartographicTransformation.h"
vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() { vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::New(); vtkNew<SpawnPointCallback> newPointCallBack;
newPointCallBack->setData(this->data); newPointCallBack->setData(this->data);
newPointCallBack->setPoints(this->points); newPointCallBack->setPoints(this->points);
newPointCallBack->setRen(this->ren); newPointCallBack->setRen(this->ren);
@ -137,6 +137,8 @@ LGlyphLayer::LGlyphLayer(std::shared_ptr<UVGrid> uvGrid, std::unique_ptr<Advecti
actor->SetMapper(this->mapper); actor->SetMapper(this->mapper);
this->ren->AddActor(actor); this->ren->AddActor(actor);
this->callback = createSpawnPointCallback();
} }
void LGlyphLayer::spoofPoints() { void LGlyphLayer::spoofPoints() {
@ -199,10 +201,15 @@ void LGlyphLayer::updateData(int t) {
} }
void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) { void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
auto newPointCallBack = createSpawnPointCallback(); interactor->AddObserver(vtkCommand::LeftButtonPressEvent, this->callback);
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, newPointCallBack); interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->callback);
interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, newPointCallBack); interactor->AddObserver(vtkCommand::MouseMoveEvent, this->callback);
interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack); }
void LGlyphLayer::removeObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
interactor->RemoveObserver(this->callback);
interactor->RemoveObserver(this->callback);
interactor->RemoveObserver(this->callback);
} }

View File

@ -23,6 +23,7 @@ private:
int dt = 3600; int dt = 3600;
int beachedAtNumberOfTimes = 20; int beachedAtNumberOfTimes = 20;
std::queue<vtkSmartPointer<vtkLookupTable>> luts; std::queue<vtkSmartPointer<vtkLookupTable>> luts;
vtkSmartPointer<SpawnPointCallback> callback;
public: public:
/** Constructor. /** Constructor.
@ -43,6 +44,7 @@ public:
vtkSmartPointer<SpawnPointCallback> createSpawnPointCallback(); vtkSmartPointer<SpawnPointCallback> createSpawnPointCallback();
void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override; void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override;
void removeObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override;
/** This function cycles which lut is used for the layer, according to the lookuptables in the luts attribute. /** This function cycles which lut is used for the layer, according to the lookuptables in the luts attribute.
*/ */

View File

@ -1,5 +1,6 @@
#include "Layer.h" #include "Layer.h"
#include <vtkRenderWindow.h> #include <vtkRenderWindow.h>
#include <vtkCamera.h>
#include <vtkRenderWindowInteractor.h> #include <vtkRenderWindowInteractor.h>
using std::string; using std::string;
@ -16,7 +17,10 @@ void Layer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor)
// By default, do nothing // By default, do nothing
} }
void Layer::removeObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
void Layer::setCamera(vtkCamera *camera) { // By default, do nothing
this->getLayer()->SetActiveCamera(camera); }
void Layer::setCamera(vtkSmartPointer<vtkCamera> cam) {
this->getLayer()->SetActiveCamera(cam.GetPointer());
} }

View File

@ -28,10 +28,16 @@ public:
*/ */
virtual void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor); virtual void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor);
/** Removes observers to the renderWindowinteractor within which this layer is active.
* @param interactor : pointer to the interactor that observers can be removed from.
*/
virtual void removeObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor);
/** Sets the active camera for the vtkRenderer associated with this layer. /** Sets the active camera for the vtkRenderer associated with this layer.
* Used to share one camera between multiple layers. * Used to share one camera between multiple layers.
*/ */
virtual void setCamera(vtkCamera *camera); virtual void setCamera(vtkSmartPointer<vtkCamera> cam);
}; };
#endif #endif

View File

@ -0,0 +1,50 @@
#include <vtkRenderWindow.h>
#include "Technique.h"
Technique::Technique(vtkSmartPointer<vtkCamera> cam) : cam(cam) {}
void Technique::addLayer(Layer *l) {
l->setCamera(this->cam);
this->layers.push_back(l);
}
void Technique::removeLayer(Layer *l) {
auto it = std::find(this->layers.begin(), this->layers.end(), l);
if (it != this->layers.end()) {
this->layers.erase(it);
}
}
void Technique::updateData(int t) {
for (Layer *l : this->layers) {
l->updateData(t);
}
}
int Technique::numberOfLayers() {
return this->layers.size();
}
void Technique::bind(vtkSmartPointer<vtkRenderWindow> win, vtkSmartPointer<vtkRenderWindowInteractor> intr) {
for (Layer *l : this->layers) {
l->addObservers(intr);
win->AddRenderer(l->getLayer());
}
win->SetNumberOfLayers(this->layers.size());
// win->Render();
}
void Technique::unbind(vtkSmartPointer<vtkRenderWindow> win, vtkSmartPointer<vtkRenderWindowInteractor> intr) {
for (Layer *l : this->layers) {
l->removeObservers(intr);
win->RemoveRenderer(l->getLayer());
}
win->SetNumberOfLayers(0);
}

View File

@ -0,0 +1,25 @@
#ifndef TECHNIQUE_H
#define TECHNIQUE_H
#include "Layer.h"
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkPolyData.h>
class Technique {
private:
std::vector<Layer *> layers;
vtkSmartPointer<vtkCamera> cam;
public:
Technique(vtkSmartPointer<vtkCamera> cam);
void addLayer(Layer *l);
void removeLayer(Layer *l);
void updateData(int t);
int numberOfLayers();
void bind(vtkSmartPointer<vtkRenderWindow> win, vtkSmartPointer<vtkRenderWindowInteractor> intr);
void unbind(vtkSmartPointer<vtkRenderWindow> win, vtkSmartPointer<vtkRenderWindowInteractor> intr);
};
#endif

View File

@ -1,49 +1,16 @@
#include <netcdf>
#include <vtkActor2D.h>
#include <vtkNamedColors.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkProperty2D.h>
#include <vtkRenderer.h>
#include <vtkVertexGlyphFilter.h>
#include <memory>
#include "layers/BackgroundImage.h"
#include "layers/EColLayer.h"
#include "layers/EGlyphLayer.h"
#include "layers/LGlyphLayer.h"
#include "Program.h"
#include "advection/UVGrid.h"
#include "advection/kernel/RK4AdvectionKernel.h"
#include "advection/kernel/SnapBoundaryConditionKernel.h"
#include <QApplication> #include <QApplication>
#include <QVTKOpenGLNativeWidget.h> #include <QVTKOpenGLNativeWidget.h>
#include <QDockWidget>
#include <QGridLayout>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QLabel>
#include <QMainWindow>
#include <QPointer>
#include <QPushButton>
#include <QVBoxLayout>
#include "QT/MainWindow.h" #include "QT/MainWindow.h"
using namespace std;
#define DT 60 * 60 // 60 sec/min * 60 mins
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat()); QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
QApplication app(argc, argv); QApplication app(argc, argv);
// Main window. MainWindow w;
MainWindow mainWindow; w.resize(1200, 900);
mainWindow.resize(1200, 900);
mainWindow.show(); w.show();
return app.exec(); return app.exec();
} }

View File

@ -1,25 +0,0 @@
#ifndef TECHNIQUE_H
#define TECHNIQUE_H
#include "layers/Layer.h"
#include <vtkPolyData.h>
class Technique {
private:
std::vector<Layer *> layers;
vtkSmartPointer<vtkPoints> points;
vtkSmartPointer<vtkPolyData> data;
void setupInteractions();
public:
Technique();
void addLayer(Layer *l);
void removeLayer(Layer *l);
void updateData(int t);
int numberOfLayers();
};
#endif