From 346e44da481ba470105e130a4b336528fe5ffc15 Mon Sep 17 00:00:00 2001 From: robin Date: Sun, 5 May 2024 14:50:26 +0200 Subject: [PATCH] normalised cartographic camera --- vtk/src/CMakeLists.txt | 1 + vtk/src/commands/TimerCallbackCommand.cpp | 2 - vtk/src/helperClasses/EGlyphLayer.cpp | 17 ++- vtk/src/helperClasses/LGlyphLayer.cpp | 104 +++++++++--------- .../NormalisedCartographicCamera.cpp | 43 ++++++++ .../NormalisedCartographicCamera.h | 8 ++ vtk/src/helperClasses/SpawnPointCallback.cpp | 15 ++- vtk/src/helperClasses/SpawnPointCallback.h | 3 + 8 files changed, 128 insertions(+), 65 deletions(-) create mode 100644 vtk/src/helperClasses/NormalisedCartographicCamera.cpp create mode 100644 vtk/src/helperClasses/NormalisedCartographicCamera.h diff --git a/vtk/src/CMakeLists.txt b/vtk/src/CMakeLists.txt index 8a20136..9cb04bc 100644 --- a/vtk/src/CMakeLists.txt +++ b/vtk/src/CMakeLists.txt @@ -46,6 +46,7 @@ add_executable(VtkBase MACOSX_BUNDLE main.cpp commands/TimerCallbackCommand.cpp helperClasses/SpawnPointCallback.h helperClasses/SpawnPointCallback.cpp + helperClasses/NormalisedCartographicCamera.cpp ) execute_process( diff --git a/vtk/src/commands/TimerCallbackCommand.cpp b/vtk/src/commands/TimerCallbackCommand.cpp index 4c43b74..d8edfd7 100644 --- a/vtk/src/commands/TimerCallbackCommand.cpp +++ b/vtk/src/commands/TimerCallbackCommand.cpp @@ -11,8 +11,6 @@ TimerCallbackCommand* TimerCallbackCommand::New(Program *program) { } void TimerCallbackCommand::Execute(vtkObject* caller, unsigned long eventId, void* vtkNotUsed(callData)) { - cout << this->time << " " << this->maxTime << endl; - this->time += this->dt; if (this->time >= this->maxTime) { diff --git a/vtk/src/helperClasses/EGlyphLayer.cpp b/vtk/src/helperClasses/EGlyphLayer.cpp index 4e4b9c0..4d3265d 100644 --- a/vtk/src/helperClasses/EGlyphLayer.cpp +++ b/vtk/src/helperClasses/EGlyphLayer.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "NormalisedCartographicCamera.h" using namespace netCDF; using namespace std; @@ -64,11 +65,15 @@ void EGlyphLayer::readCoordinates() { this->direction->SetNumberOfTuples(numLats*numLons); points->Allocate(numLats*numLons); + auto camera = createNormalisedCartographicCamera(); + ren->SetActiveCamera(camera); + int i = 0; for (double lat : lats) { for (double lon : lons) { + cout << "lon: " << lon << " lat: " << lat << endl; direction->SetTuple3(i, 0.45, 0.90, 0); //FIXME: read this info from file - points->InsertPoint(i++, (lat*1000-46125)/25, (lon*1000+15875)/43.5, 0); // FIXME: counts on fixed window geometry to map properly; refactor to make use of active window geometry. + points->InsertPoint(i++, lon, lat, 0); // FIXME: counts on fixed window geometry to map properly; refactor to make use of active window geometry. // see also https://vtk.org/doc/nightly/html/classvtkPolyDataMapper2D.html } } @@ -78,7 +83,7 @@ void EGlyphLayer::readCoordinates() { vtkNew arrowSource; arrowSource->SetGlyphTypeToArrow(); - arrowSource->SetScale(8); //TODO: set this properly + arrowSource->SetScale(0.2); //TODO: set this properly arrowSource->Update(); vtkNew glyph2D; @@ -90,15 +95,15 @@ void EGlyphLayer::readCoordinates() { glyph2D->SetVectorModeToUseVector(); glyph2D->Update(); - vtkNew coordinate; - coordinate->SetCoordinateSystemToWorld(); +// vtkNew coordinate; +// coordinate->SetCoordinateSystemToWorld(); - vtkNew(mapper); + vtkNew(mapper); // mapper->SetTransformCoordinate(coordinate); mapper->SetInputConnection(glyph2D->GetOutputPort()); mapper->Update(); - vtkNew actor; + vtkNew actor; actor->SetMapper(mapper); actor->GetProperty()->SetColor(0,0,0); diff --git a/vtk/src/helperClasses/LGlyphLayer.cpp b/vtk/src/helperClasses/LGlyphLayer.cpp index e3d10d2..00e3ef5 100644 --- a/vtk/src/helperClasses/LGlyphLayer.cpp +++ b/vtk/src/helperClasses/LGlyphLayer.cpp @@ -9,16 +9,23 @@ #include #include #include +#include +#include +#include +#include +#include + +#include "NormalisedCartographicCamera.h" vtkSmartPointer LGlyphLayer::createSpawnPointCallback() { auto newPointCallBack = vtkSmartPointer::New(); newPointCallBack->setData(data); newPointCallBack->setPoints(points); + newPointCallBack->setRen(ren); return newPointCallBack; } - // TODO: add interactionStyle functionality // TODO: add timer + advection (probably from the program class not here) // TODO: how do we handle mapping between pixelspace and lat/lon (needed for advection)? Current idea: store the vtkPoints in lat/lon system, then apply a transformfilter to map them to the current window geometry. This should allow for a changing viewport as well - we can query the new camera position and map accordingly. @@ -28,74 +35,61 @@ vtkSmartPointer LGlyphLayer::createSpawnPointCallback() { // TODO: modelling all this in vtkClasses is workable, but ideally i would want to work with a native C++ class. See if this is doable and feasible. LGlyphLayer::LGlyphLayer() { - this->ren = vtkSmartPointer::New(); - this->ren->SetLayer(2); + this->ren = vtkSmartPointer::New(); + this->ren->SetLayer(2); - this->points = vtkSmartPointer::New(); - this->data = vtkSmartPointer::New(); - this->data->SetPoints(this->points); - - vtkNew circleSource; - circleSource->SetGlyphTypeToCircle(); - circleSource->SetScale(15); - circleSource->Update(); + this->points = vtkSmartPointer::New(); + this->data = vtkSmartPointer::New(); + this->data->SetPoints(this->points); - vtkNew glyph2D; - glyph2D->SetSourceConnection(circleSource->GetOutputPort()); - glyph2D->SetInputData(this->data); - glyph2D->SetColorModeToColorByScalar(); - glyph2D->Update(); + vtkNew circleSource; + circleSource->SetGlyphTypeToCircle(); + circleSource->SetScale(1); + circleSource->Update(); - vtkNew mapper; - mapper->SetInputConnection(glyph2D->GetOutputPort()); - mapper->Update(); + vtkNew glyph2D; + glyph2D->SetSourceConnection(circleSource->GetOutputPort()); + glyph2D->SetInputData(this->data); + glyph2D->SetColorModeToColorByScalar(); + glyph2D->Update(); - vtkNew actor; - actor->SetMapper(mapper); - actor->GetProperty()->SetColor(1,1,1); + auto camera = createNormalisedCartographicCamera(); + ren->SetActiveCamera(camera); - this->ren->AddActor(actor); + vtkNew mapper; + mapper->SetInputConnection(glyph2D->GetOutputPort()); + mapper->Update(); + + vtkNew actor; + actor->SetMapper(mapper); + + this->ren->AddActor(actor); } // creates a few points so we can test the updateData function void LGlyphLayer::spoofPoints() { - this->points->InsertNextPoint(53, 2, 0); - this->points->InsertNextPoint(48.2, 111.01, 0); - this->points->InsertNextPoint(331, 331, 0); +// this->points->InsertNextPoint(200, 200 , 0); + this->points->InsertNextPoint(-4.125, 61.375 , 0); + this->points->InsertNextPoint(4.896555178870355, 52.373557841669516, 0); +// this->points->InsertNextPoint(48.2, 111.01, 0); +// this->points->InsertNextPoint(331, 331, 0); +// this->points->InsertNextPoint(0, 50, 0); +// this->points->InsertNextPoint(200, 200 , 0); - this->points->Modified(); + this->points->Modified(); } - // returns new coords for a point; used to test the updateData function std::pair advect(int time, double lat, double lon) { - return {lat+0.1, lon+0.1} ; + return {lat + 0., lon + 0.}; } - -// converts a x,y pair from pixel coordinates to real world latitude and longitude. -// TODO: make this more modular by having it interact with the backgroundImage layer (and possibly the camera panning/zooming logic when that is implemented). -std::pair pixelToReal(double x, double y) { - //assumes a 661x661 window with a range of [46.125, 62.625] lat and [-15.875, 12.875] lon. - return {(x*25+46125)/1000, (y*43.5-15875)/1000}; -} - -// converts a lat,lon pair from real world values to pixel coordinates. -// TODO: see above. -std::pair realToPixel(double lat, double lon) { - //assumes a 661x661 window with a range of [46.125, 62.625] lat and [-15.875, 12.875] lon. - return {(lat*1000-46125)/25, (lon*1000+15875)/43.5}; -} - -// FIXME: actually the above functions are a bit of a naive way of modelling these. Much better would be to have the points at the real-world latitude and longitude, and apply a filter in the pipeline to convert them to the appropriate window geometry. - void LGlyphLayer::updateData(int t) { - double point[3]; - for (vtkIdType n=0; n < this->points->GetNumberOfPoints(); n++) { - this->points->GetPoint(n, point); - auto grads = pixelToReal(point[0], point[1]); - auto newGrads = advect(n, grads.first, grads.second); - auto newPixs = realToPixel(newGrads.first, newGrads.second); - this->points->SetPoint(n, newPixs.first, newPixs.second, 0); - } - this->points->Modified(); +void LGlyphLayer::updateData(int t) { + double point[3]; + for (vtkIdType n = 0; n < this->points->GetNumberOfPoints(); n++) { + this->points->GetPoint(n, point); + auto [xNew, yNew] = advect(n, point[0], point[1]); + this->points->SetPoint(n, xNew, yNew, 0); + } + this->points->Modified(); } diff --git a/vtk/src/helperClasses/NormalisedCartographicCamera.cpp b/vtk/src/helperClasses/NormalisedCartographicCamera.cpp new file mode 100644 index 0000000..d34bafe --- /dev/null +++ b/vtk/src/helperClasses/NormalisedCartographicCamera.cpp @@ -0,0 +1,43 @@ +#include "NormalisedCartographicCamera.h" +#include + +vtkSmartPointer createNormalisedCartographicCamera() { + const double XMin = -15.875; + const double XMax = 12.875; + const double YMin = 46.125; + const double YMax = 62.625; + + double farClipPlane = 100; + double nearClipPlane = 1; + double eyeTransform[] = { + 2/(XMax-XMin), 0, 0, -(XMax+XMin)/(XMax-XMin), + 0, 2/(YMax-YMin), 0, -(YMax+YMin)/(YMax-YMin), + 0, 0, 2/(nearClipPlane-farClipPlane), -(farClipPlane+nearClipPlane)/(farClipPlane-nearClipPlane), + 0, 0, 0, 1 + }; + + vtkSmartPointer camera = vtkSmartPointer::New(); + camera->ParallelProjectionOn(); // Enable parallel projection + camera->UseExplicitProjectionTransformMatrixOn(); + +//// // Calculate the center and the size of the view + double centerX = (XMax + XMin) / 2.0; + double centerY = (YMax + YMin) / 2.0; + double width = XMax - XMin; + double height = YMax - YMin; +//// // Set the camera position, focal point, and view up +// camera->SetPosition(centerX, centerY, 1000); // Place the camera above the center +// camera->SetFocalPoint(centerX, centerY, 0); // Look at the center +// camera->SetViewUp(0, 1, 0); // Set the up vector to be along the Y-axis +//// +//// // Set parallel scale +// double parallelScale = std::max(width, height) / 2.0; +// camera->SetParallelScale(parallelScale); + + vtkNew projectionMatrix; + projectionMatrix->DeepCopy(eyeTransform); + camera->SetExplicitProjectionTransformMatrix(projectionMatrix); +// camera->SetScreenBottomLeft(XMin, YMin, 0); +// camera->SetScreenTopRight(XMax, YMax, 0); + return camera; +} diff --git a/vtk/src/helperClasses/NormalisedCartographicCamera.h b/vtk/src/helperClasses/NormalisedCartographicCamera.h new file mode 100644 index 0000000..fca5a39 --- /dev/null +++ b/vtk/src/helperClasses/NormalisedCartographicCamera.h @@ -0,0 +1,8 @@ +#include + +#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H +#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H + +#endif //VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H + +vtkSmartPointer createNormalisedCartographicCamera(); \ No newline at end of file diff --git a/vtk/src/helperClasses/SpawnPointCallback.cpp b/vtk/src/helperClasses/SpawnPointCallback.cpp index 14dbc49..15eca3b 100644 --- a/vtk/src/helperClasses/SpawnPointCallback.cpp +++ b/vtk/src/helperClasses/SpawnPointCallback.cpp @@ -31,7 +31,14 @@ void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *ca int x, y; interactor->GetEventPosition(x, y); - vtkIdType id = points->InsertNextPoint(x, y, 0); + double worldPos[4] = {2, 0 ,0, 0}; + double displayPos[3] = {static_cast(x), static_cast(y), 0.0}; + ren->SetDisplayPoint(displayPos); + ren->DisplayToWorld(); + ren->GetWorldPoint(worldPos); + cout << "clicked on lon = " << worldPos[0] << " and lat = " << worldPos[1] << endl; + + vtkIdType id = points->InsertNextPoint(worldPos[0], worldPos[1], 0); data->SetPoints(points); vtkSmartPointer vertex = vtkSmartPointer::New(); @@ -57,4 +64,8 @@ void SpawnPointCallback::setData(const vtkSmartPointer &data) { void SpawnPointCallback::setPoints(const vtkSmartPointer &points) { this->points = points; -} \ No newline at end of file +} + +void SpawnPointCallback::setRen(const vtkSmartPointer &ren) { + this->ren = ren; +} diff --git a/vtk/src/helperClasses/SpawnPointCallback.h b/vtk/src/helperClasses/SpawnPointCallback.h index 99ab160..e71063d 100644 --- a/vtk/src/helperClasses/SpawnPointCallback.h +++ b/vtk/src/helperClasses/SpawnPointCallback.h @@ -17,9 +17,12 @@ public: void setData(const vtkSmartPointer &data); + void setRen(const vtkSmartPointer &ren); + private: vtkSmartPointer data; vtkSmartPointer points; + vtkSmartPointer ren; public: private: