feat: legend

This commit is contained in:
Djairo Hougee 2024-05-30 04:42:45 +02:00
parent cb20cc0bd0
commit 039163e8f0
8 changed files with 188 additions and 12 deletions

View File

@ -59,6 +59,8 @@ add_executable(ParticleTrackTrace MACOSX_BUNDLE main.cpp
layers/Technique.cpp
layers/Technique.h
layers/enums.h
layers/LegendLayer.h
layers/LegendLayer.cpp
layers/luts.cpp
layers/luts.h
Program.cpp

View File

@ -19,6 +19,7 @@
#include "../layers/LColLayer.h"
#include "../layers/LGlyphLayer.h"
#include "../layers/enums.h"
#include "../layers/LegendLayer.h"
using namespace std;
@ -52,6 +53,10 @@ void MainWindow::setupTechniques() {
technique1->addLayer(bg);
technique2->addLayer(bg);
// add legend layer
technique1->addLayer(new LegendLayer(dataPath + "/legends", "COLGLYPH"));
technique2->addLayer(new LegendLayer(dataPath + "/legends", "GLYPHCOL"));
// add Euler layers
technique1->addLayer(new EColLayer(uvGrid));
technique2->addLayer(new EGlyphLayer(uvGrid));

View File

@ -182,6 +182,7 @@ void EColLayer::setSaturationMode(SaturationMode mode) {
int calcIndex(double u, double v, double maxStren) {
if (not u and not v) return -1;
int angleIdx = calcAngleIndex(u,v);
int strIdx = calcStrengthIndex(u,v, maxStren);

View File

@ -125,7 +125,7 @@ LColLayer::LColLayer(shared_ptr<UVGrid> uvGrid, unique_ptr<AdvectionKernel> adve
vtkNew<vtkActor> actor;
actor->SetMapper(this->mapper);
// actor->GetProperty()->SetOpacity(0.5);
actor->GetProperty()->SetOpacity(0.5);
actor->GetProperty()->SetOpacity(1);
this->ren->AddActor(actor);

View File

@ -0,0 +1,123 @@
#include "LegendLayer.h"
#include <vtkImageDataGeometryFilter.h>
#include <vtkImageReader2Factory.h>
#include <vtkPolyDataMapper.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
using std::string;
LegendLayer::LegendLayer(string legendPath, string techName) : legendPath(legendPath), techName(techName) {
this->ren = vtkSmartPointer<vtkRenderer>::New();
this->ren->SetLayer(3);
this->ren->InteractiveOff();
this->activeColourMode = COMPLEMENTARY;
this->activeSaturationMode = SATURATED;
addLegends();
//setup pipeline
// translates an image such that the middle is at (0,0)
this->imageCenterer = vtkSmartPointer<vtkImageChangeInformation>::New();
this->imageCenterer->SetInputConnection(this->readers[0]->GetOutputPort());
this->imageCenterer->CenterImageOn();
this->imageCenterer->Update();
// get some info from the data we'll need in a second
// FIXME: not updating this value means differently sized images are not properly scaled.
vtkSmartPointer<vtkImageData> imageData = imageCenterer->GetOutput();
double origin[3];
int extent[6];
imageData->GetOrigin(origin);
imageData->GetExtent(extent);
// map the imageData to a vtkPolydata so we can use a vtkTransform
vtkNew<vtkImageDataGeometryFilter> imageDataGeometryFilter;
imageDataGeometryFilter->SetInputData(imageData);
imageDataGeometryFilter->Update();
// setup the vtkTransform - this is where use the data from imageData we got earlier
vtkNew<vtkTransform> transform;
transform->Identity();
// FIXME: can be improved for one matrix instead.
transform->Concatenate(toDesiredMatrix(0.5, -0.5, 1, -1));
transform->Concatenate(toNormalisedMatrix(origin[0], origin[1], extent[1]+origin[0], extent[3]+origin[1]));
vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
transformFilter->SetTransform(transform);
transformFilter->SetInputConnection(imageDataGeometryFilter->GetOutputPort());
transformFilter->Update();
// Create a mapper and actor
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(transformFilter->GetOutputPort());
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
this->ren->AddActor(actor);
setColourMode(COMPLEMENTARY);
}
void LegendLayer::addLegends() {
this->readers.push_back(readImage(this->legendPath + "/" + this->techName + "_complementary.png"));
this->readers.push_back(readImage(this->legendPath + "/" + this->techName + "_contrasting.png"));
this->readers.push_back(readImage(this->legendPath + "/" + this->techName + "_monochromatic.png"));
this->readers.push_back(readImage(this->legendPath + "/" + this->techName + "_desaturated.png"));
}
vtkSmartPointer<vtkImageReader2> LegendLayer::readImage(string path) {
vtkNew<vtkImageReader2Factory> readerFactory;
vtkSmartPointer<vtkImageReader2> imageReader;
imageReader.TakeReference(readerFactory->CreateImageReader2(path.c_str()));
imageReader->SetFileName(path.c_str());
imageReader->Update();
return imageReader;
}
void LegendLayer::setColourMode(ColourMode mode) {
this->activeColourMode = mode;
if (this->activeSaturationMode == DESATURATED) return;
this->imageCenterer->SetInputConnection(this->readers[mode]->GetOutputPort());
imageCenterer->Update();
}
void LegendLayer::setSaturationMode(SaturationMode mode) {
this->activeSaturationMode = mode;
if (mode == DESATURATED) {
this->imageCenterer->SetInputConnection(this->readers[mode]->GetOutputPort());
} else {
this->imageCenterer->SetInputConnection(this->readers[this->activeColourMode]->GetOutputPort());
}
imageCenterer->Update();
}
// transforms from [0,1] x [0,1] to [x0, xMax] x [y0, yMax]
vtkSmartPointer<vtkMatrix4x4> toDesiredMatrix(const double x0, const double y0, const int xMax, const int yMax) {
double eyeTransform[] = {
xMax-x0, 0, 0, x0,
0, yMax-y0, 0, y0,
0, 0, 1, 0,
0, 0, 0, 1
};
auto matrix = vtkSmartPointer<vtkMatrix4x4>::New();
matrix->DeepCopy(eyeTransform);
return matrix;
}
// transform image from [x0, xMax] x [y0, yMax] to [0,1] x [0,1]
vtkSmartPointer<vtkMatrix4x4> toNormalisedMatrix(const double x0, const double y0, const int xMax, const int yMax) {
double eyeTransform[] = {
1/(xMax-x0), 0, 0, 0.5-(xMax+x0)/(2*(xMax-x0)),
0, 1/(yMax-y0), 0, 0.5-(yMax+y0)/(2*(yMax-y0)),
0, 0, 1, 0,
0, 0, 0, 1
};
auto matrix = vtkSmartPointer<vtkMatrix4x4>::New();
matrix->DeepCopy(eyeTransform);
return matrix;
}

View File

@ -0,0 +1,34 @@
#ifndef LEGENDLAYER_H
#define LEGENDLAYER_H
#include "Layer.h"
#include <vtkImageChangeInformation.h>
#include <vtkImageData.h>
#include <vtkImageReader2.h>
class LegendLayer : public Layer {
private:
std::vector<vtkSmartPointer<vtkImageReader2>> readers;
vtkSmartPointer<vtkImageChangeInformation> imageCenterer;
ColourMode activeColourMode;
SaturationMode activeSaturationMode;
std::string legendPath;
std::string techName;
void addLegends();
vtkSmartPointer<vtkImageReader2> readImage(std::string path);
public:
LegendLayer(std::string imagePath, std::string techName);
void setColourMode(ColourMode mode) override;
void setSaturationMode(SaturationMode mode) override;
};
vtkSmartPointer<vtkMatrix4x4> toDesiredMatrix(const double x0, const double y0, const int xMax, const int yMax);
vtkSmartPointer<vtkMatrix4x4> toNormalisedMatrix(const double x0, const double y0, const int xMax, const int yMax);
#endif

View File

@ -88,6 +88,8 @@ vtkSmartPointer<vtkLookupTable> buildCyclicComplementary() {
lut->SetTableValue(idx++, 0.247059, 0.243137, 0.227451, opacity);
}
lut->SetBelowRangeColor(0,0,0,0);
lut->UseBelowRangeColorOn();
lut->SetNanColor(0.0,0,0,0);
return lut;
}
@ -116,6 +118,8 @@ vtkSmartPointer<vtkLookupTable> buildCyclicContrasting() {
lut->SetTableValue(idx++, 0.447059, 0.223529, 0.34902, opacity);
}
lut->SetBelowRangeColor(0,0,0,0);
lut->UseBelowRangeColorOn();
lut->SetNanColor(0.0,0,0,0);
return lut;
}
@ -144,6 +148,8 @@ vtkSmartPointer<vtkLookupTable> buildCyclicMonochromatic() {
lut->SetTableValue(idx++, 0.180392, 0.494118, 0.698039, opacity);
}
lut->SetBelowRangeColor(0,0,0,0);
lut->UseBelowRangeColorOn();
lut->SetNanColor(0.0,0,0,0);
return lut;
}
@ -160,18 +166,20 @@ vtkSmartPointer<vtkLookupTable> buildCyclicDesaturated() {
int idx=0.0;
for (double opacity=0.1; opacity <= 1.0; opacity+=0.1) {
lut->SetTableValue(idx++, 44, 44, 44, opacity);
lut->SetTableValue(idx++, 56, 56, 56, opacity);
lut->SetTableValue(idx++, 85, 85, 85, opacity);
lut->SetTableValue(idx++, 114, 114, 114, opacity);
lut->SetTableValue(idx++, 149, 149, 149, opacity);
lut->SetTableValue(idx++, 146, 146, 146, opacity);
lut->SetTableValue(idx++, 110, 110, 110, opacity);
lut->SetTableValue(idx++, 78, 78, 78, opacity);
lut->SetTableValue(idx++, 52, 52, 52, opacity);
lut->SetTableValue(idx++, 45, 45, 45, opacity);
lut->SetTableValue(idx++, 0.172549, 0.172549, 0.172549, opacity);
lut->SetTableValue(idx++, 0.219608, 0.219608, 0.219608, opacity);
lut->SetTableValue(idx++, 0.333333, 0.333333, 0.333333, opacity);
lut->SetTableValue(idx++, 0.447059, 0.447059, 0.447059, opacity);
lut->SetTableValue(idx++, 0.584314, 0.584314, 0.584314, opacity);
lut->SetTableValue(idx++, 0.572549, 0.572549, 0.572549, opacity);
lut->SetTableValue(idx++, 0.431373, 0.431373, 0.431373, opacity);
lut->SetTableValue(idx++, 0.305882, 0.305882, 0.305882, opacity);
lut->SetTableValue(idx++, 0.203922, 0.203922, 0.203922, opacity);
lut->SetTableValue(idx++, 0.176471, 0.176471, 0.176471, opacity);
}
lut->SetBelowRangeColor(0,0,0,0);
lut->UseBelowRangeColorOn();
lut->SetNanColor(0.0,0,0,0);
return lut;
}

View File

@ -2,7 +2,7 @@
#include <QVTKOpenGLNativeWidget.h>
#include "QT/MainWindow.h"
// TODO: add a widget to act as legend. This is fourfold: particle-age, LCol-density, Lcol-age, ECol-direction ECol-strength?
// TODO: add a widget to act as legend. This is fourfold: LCol-density, Lcol-age, ECol-strength?
// TODO: add text widget showing simulation time (in days/weeks/months from 0).
// TODO: make Lagrangian Layers share one vtkPoints for seemless technique switching
// TODO: make LColLayer use a modified spawnpointCallback to spawn multiple particles per interaction
@ -10,6 +10,9 @@
// TODO: yoink Robin's isNearestNeighbourZero function to improve beaching
// TODO: add a button to reset the simulation - set time=0 and reset points array of particles.
// FIXME: go over each function and add const where appropriate.
// FIXME: rotate ECol monochromatic layer
// COULDHAVE: the Legends are just statically rendered images; ideally these would be created along with the luts and then displayed accordingly.
int main(int argc, char* argv[]) {
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());