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/LGlyphLayer.cpp
layers/LGlyphLayer.h
layers/Technique.cpp
layers/Technique.h
Program.cpp
Program.h
commands/TimerCallbackCommand.h

View File

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

View File

@ -7,6 +7,7 @@
#include <vtkRenderer.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.
* 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
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.
*/
// vtkSmartPointer<vtkRenderWindow> win;
vtkSmartPointer<vtkGenericOpenGLRenderWindow> win;
/** The interactor through which the layers can interact with the window.
*/
vtkSmartPointer<vtkRenderWindowInteractor> interact;
// vtkSmartPointer<QVTKInteractor> interact;
/** The camera used by all layers for this program.
@ -53,33 +54,30 @@ public:
Program(QWidget *parent = nullptr);
~Program() override;
/** This function adds a new layer (and thus vtkRenderer) to the program.
* The layer is expected to set its own position in the vtkRenderWindow layer system.
* @param layer : pointer to the layer to add.
/** This function adds a new technique to the program.
* The technique is expected to manage the layers itself in the vtkRenderWindow layer system.
* @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.
* 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.
* @param t : the timestamp to update the data to.
*/
void updateData(int t);
/** This function adds all interactors of each layer to the interactor/window
*/
void setupInteractions();
/**
* This function renders the vtkRenderWindow for the first time.
* Only call this function once!
*/
void render();
// 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...
void setActiveTechnique(int idx);
vtkSmartPointer<vtkCamera> getCamera();
};

View File

@ -22,28 +22,7 @@ MainWindow::MainWindow(QWidget* parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
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();
this->setupTechniques();
}
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 +
* --------------------------------------------------------------------*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,10 +28,16 @@ public:
*/
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.
* Used to share one camera between multiple layers.
*/
virtual void setCamera(vtkCamera *camera);
virtual void setCamera(vtkSmartPointer<vtkCamera> cam);
};
#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 <QVTKOpenGLNativeWidget.h>
#include <QDockWidget>
#include <QGridLayout>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QLabel>
#include <QMainWindow>
#include <QPointer>
#include <QPushButton>
#include <QVBoxLayout>
#include "QT/MainWindow.h"
using namespace std;
#define DT 60 * 60 // 60 sec/min * 60 mins
int main(int argc, char* argv[]) {
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
QApplication app(argc, argv);
// Main window.
MainWindow mainWindow;
mainWindow.resize(1200, 900);
MainWindow w;
w.resize(1200, 900);
mainWindow.show();
w.show();
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