From 039163e8f03ec2f2287cfeb6ff1e3b845f6c5c42 Mon Sep 17 00:00:00 2001 From: djairoh Date: Thu, 30 May 2024 04:42:45 +0200 Subject: [PATCH] feat: legend --- particle-track-and-trace/src/CMakeLists.txt | 2 + .../src/QT/MainWindow.cpp | 5 + .../src/layers/EColLayer.cpp | 1 + .../src/layers/LColLayer.cpp | 2 +- .../src/layers/LegendLayer.cpp | 123 ++++++++++++++++++ .../src/layers/LegendLayer.h | 34 +++++ particle-track-and-trace/src/layers/luts.cpp | 28 ++-- particle-track-and-trace/src/main.cpp | 5 +- 8 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 particle-track-and-trace/src/layers/LegendLayer.cpp create mode 100644 particle-track-and-trace/src/layers/LegendLayer.h diff --git a/particle-track-and-trace/src/CMakeLists.txt b/particle-track-and-trace/src/CMakeLists.txt index fcd6180..11767a0 100644 --- a/particle-track-and-trace/src/CMakeLists.txt +++ b/particle-track-and-trace/src/CMakeLists.txt @@ -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 diff --git a/particle-track-and-trace/src/QT/MainWindow.cpp b/particle-track-and-trace/src/QT/MainWindow.cpp index 8d7ec6f..8935353 100644 --- a/particle-track-and-trace/src/QT/MainWindow.cpp +++ b/particle-track-and-trace/src/QT/MainWindow.cpp @@ -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)); diff --git a/particle-track-and-trace/src/layers/EColLayer.cpp b/particle-track-and-trace/src/layers/EColLayer.cpp index aa10f6f..0cb28eb 100644 --- a/particle-track-and-trace/src/layers/EColLayer.cpp +++ b/particle-track-and-trace/src/layers/EColLayer.cpp @@ -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); diff --git a/particle-track-and-trace/src/layers/LColLayer.cpp b/particle-track-and-trace/src/layers/LColLayer.cpp index 9d4afff..c2a151c 100644 --- a/particle-track-and-trace/src/layers/LColLayer.cpp +++ b/particle-track-and-trace/src/layers/LColLayer.cpp @@ -125,7 +125,7 @@ LColLayer::LColLayer(shared_ptr uvGrid, unique_ptr adve vtkNew actor; actor->SetMapper(this->mapper); - // actor->GetProperty()->SetOpacity(0.5); + actor->GetProperty()->SetOpacity(0.5); actor->GetProperty()->SetOpacity(1); this->ren->AddActor(actor); diff --git a/particle-track-and-trace/src/layers/LegendLayer.cpp b/particle-track-and-trace/src/layers/LegendLayer.cpp new file mode 100644 index 0000000..6ffbbf1 --- /dev/null +++ b/particle-track-and-trace/src/layers/LegendLayer.cpp @@ -0,0 +1,123 @@ +#include "LegendLayer.h" +#include +#include +#include +#include +#include + +using std::string; + +LegendLayer::LegendLayer(string legendPath, string techName) : legendPath(legendPath), techName(techName) { + this->ren = vtkSmartPointer::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::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 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 imageDataGeometryFilter; + imageDataGeometryFilter->SetInputData(imageData); + imageDataGeometryFilter->Update(); + + // setup the vtkTransform - this is where use the data from imageData we got earlier + vtkNew 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 transformFilter = vtkSmartPointer::New(); + transformFilter->SetTransform(transform); + transformFilter->SetInputConnection(imageDataGeometryFilter->GetOutputPort()); + transformFilter->Update(); + + // Create a mapper and actor + vtkNew mapper; + mapper->SetInputConnection(transformFilter->GetOutputPort()); + + vtkNew 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 LegendLayer::readImage(string path) { + vtkNew readerFactory; + vtkSmartPointer 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 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::New(); + matrix->DeepCopy(eyeTransform); + return matrix; +} + +// transform image from [x0, xMax] x [y0, yMax] to [0,1] x [0,1] +vtkSmartPointer 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::New(); + matrix->DeepCopy(eyeTransform); + return matrix; +} diff --git a/particle-track-and-trace/src/layers/LegendLayer.h b/particle-track-and-trace/src/layers/LegendLayer.h new file mode 100644 index 0000000..2042706 --- /dev/null +++ b/particle-track-and-trace/src/layers/LegendLayer.h @@ -0,0 +1,34 @@ +#ifndef LEGENDLAYER_H +#define LEGENDLAYER_H + +#include "Layer.h" +#include +#include +#include + + +class LegendLayer : public Layer { +private: + std::vector> readers; + vtkSmartPointer imageCenterer; + ColourMode activeColourMode; + SaturationMode activeSaturationMode; + std::string legendPath; + std::string techName; + + void addLegends(); + vtkSmartPointer readImage(std::string path); + + + + +public: + LegendLayer(std::string imagePath, std::string techName); + void setColourMode(ColourMode mode) override; + void setSaturationMode(SaturationMode mode) override; +}; + + +vtkSmartPointer toDesiredMatrix(const double x0, const double y0, const int xMax, const int yMax); +vtkSmartPointer toNormalisedMatrix(const double x0, const double y0, const int xMax, const int yMax); +#endif diff --git a/particle-track-and-trace/src/layers/luts.cpp b/particle-track-and-trace/src/layers/luts.cpp index 56b1745..855228b 100644 --- a/particle-track-and-trace/src/layers/luts.cpp +++ b/particle-track-and-trace/src/layers/luts.cpp @@ -88,6 +88,8 @@ vtkSmartPointer 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 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 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 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; } diff --git a/particle-track-and-trace/src/main.cpp b/particle-track-and-trace/src/main.cpp index 449ab0e..67cd558 100644 --- a/particle-track-and-trace/src/main.cpp +++ b/particle-track-and-trace/src/main.cpp @@ -2,7 +2,7 @@ #include #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());