normalised cartographic camera

This commit is contained in:
robin 2024-05-05 14:50:26 +02:00
parent 06315a3d52
commit 346e44da48
8 changed files with 128 additions and 65 deletions

View File

@ -46,6 +46,7 @@ add_executable(VtkBase MACOSX_BUNDLE main.cpp
commands/TimerCallbackCommand.cpp commands/TimerCallbackCommand.cpp
helperClasses/SpawnPointCallback.h helperClasses/SpawnPointCallback.h
helperClasses/SpawnPointCallback.cpp helperClasses/SpawnPointCallback.cpp
helperClasses/NormalisedCartographicCamera.cpp
) )
execute_process( execute_process(

View File

@ -11,8 +11,6 @@ TimerCallbackCommand* TimerCallbackCommand::New(Program *program) {
} }
void TimerCallbackCommand::Execute(vtkObject* caller, unsigned long eventId, void* vtkNotUsed(callData)) { void TimerCallbackCommand::Execute(vtkObject* caller, unsigned long eventId, void* vtkNotUsed(callData)) {
cout << this->time << " " << this->maxTime << endl;
this->time += this->dt; this->time += this->dt;
if (this->time >= this->maxTime) { if (this->time >= this->maxTime) {

View File

@ -13,6 +13,7 @@
#include <vtkVertexGlyphFilter.h> #include <vtkVertexGlyphFilter.h>
#include <netcdf> #include <netcdf>
#include <vtkArrowSource.h> #include <vtkArrowSource.h>
#include "NormalisedCartographicCamera.h"
using namespace netCDF; using namespace netCDF;
using namespace std; using namespace std;
@ -64,11 +65,15 @@ void EGlyphLayer::readCoordinates() {
this->direction->SetNumberOfTuples(numLats*numLons); this->direction->SetNumberOfTuples(numLats*numLons);
points->Allocate(numLats*numLons); points->Allocate(numLats*numLons);
auto camera = createNormalisedCartographicCamera();
ren->SetActiveCamera(camera);
int i = 0; int i = 0;
for (double lat : lats) { for (double lat : lats) {
for (double lon : lons) { for (double lon : lons) {
cout << "lon: " << lon << " lat: " << lat << endl;
direction->SetTuple3(i, 0.45, 0.90, 0); //FIXME: read this info from file 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 // see also https://vtk.org/doc/nightly/html/classvtkPolyDataMapper2D.html
} }
} }
@ -78,7 +83,7 @@ void EGlyphLayer::readCoordinates() {
vtkNew<vtkGlyphSource2D> arrowSource; vtkNew<vtkGlyphSource2D> arrowSource;
arrowSource->SetGlyphTypeToArrow(); arrowSource->SetGlyphTypeToArrow();
arrowSource->SetScale(8); //TODO: set this properly arrowSource->SetScale(0.2); //TODO: set this properly
arrowSource->Update(); arrowSource->Update();
vtkNew<vtkGlyph2D> glyph2D; vtkNew<vtkGlyph2D> glyph2D;
@ -90,15 +95,15 @@ void EGlyphLayer::readCoordinates() {
glyph2D->SetVectorModeToUseVector(); glyph2D->SetVectorModeToUseVector();
glyph2D->Update(); glyph2D->Update();
vtkNew<vtkCoordinate> coordinate; // vtkNew<vtkCoordinate> coordinate;
coordinate->SetCoordinateSystemToWorld(); // coordinate->SetCoordinateSystemToWorld();
vtkNew<vtkPolyDataMapper2D>(mapper); vtkNew<vtkPolyDataMapper>(mapper);
// mapper->SetTransformCoordinate(coordinate); // mapper->SetTransformCoordinate(coordinate);
mapper->SetInputConnection(glyph2D->GetOutputPort()); mapper->SetInputConnection(glyph2D->GetOutputPort());
mapper->Update(); mapper->Update();
vtkNew<vtkActor2D> actor; vtkNew<vtkActor> actor;
actor->SetMapper(mapper); actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0,0,0); actor->GetProperty()->SetColor(0,0,0);

View File

@ -9,16 +9,23 @@
#include <vtkVertexGlyphFilter.h> #include <vtkVertexGlyphFilter.h>
#include <vtkInteractorStyle.h> #include <vtkInteractorStyle.h>
#include <vtkInteractorStyleUser.h> #include <vtkInteractorStyleUser.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkCamera.h>
#include "NormalisedCartographicCamera.h"
vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() { vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::New(); auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::New();
newPointCallBack->setData(data); newPointCallBack->setData(data);
newPointCallBack->setPoints(points); newPointCallBack->setPoints(points);
newPointCallBack->setRen(ren);
return newPointCallBack; return newPointCallBack;
} }
// TODO: add interactionStyle functionality // TODO: add interactionStyle functionality
// TODO: add timer + advection (probably from the program class not here) // 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. // 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.
@ -37,7 +44,7 @@ LGlyphLayer::LGlyphLayer() {
vtkNew<vtkGlyphSource2D> circleSource; vtkNew<vtkGlyphSource2D> circleSource;
circleSource->SetGlyphTypeToCircle(); circleSource->SetGlyphTypeToCircle();
circleSource->SetScale(15); circleSource->SetScale(1);
circleSource->Update(); circleSource->Update();
vtkNew<vtkGlyph2D> glyph2D; vtkNew<vtkGlyph2D> glyph2D;
@ -46,56 +53,43 @@ LGlyphLayer::LGlyphLayer() {
glyph2D->SetColorModeToColorByScalar(); glyph2D->SetColorModeToColorByScalar();
glyph2D->Update(); glyph2D->Update();
vtkNew<vtkPolyDataMapper2D> mapper; auto camera = createNormalisedCartographicCamera();
ren->SetActiveCamera(camera);
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(glyph2D->GetOutputPort()); mapper->SetInputConnection(glyph2D->GetOutputPort());
mapper->Update(); mapper->Update();
vtkNew<vtkActor2D> actor; vtkNew<vtkActor> actor;
actor->SetMapper(mapper); actor->SetMapper(mapper);
actor->GetProperty()->SetColor(1,1,1);
this->ren->AddActor(actor); this->ren->AddActor(actor);
} }
// creates a few points so we can test the updateData function // creates a few points so we can test the updateData function
void LGlyphLayer::spoofPoints() { void LGlyphLayer::spoofPoints() {
this->points->InsertNextPoint(53, 2, 0); // this->points->InsertNextPoint(200, 200 , 0);
this->points->InsertNextPoint(48.2, 111.01, 0); this->points->InsertNextPoint(-4.125, 61.375 , 0);
this->points->InsertNextPoint(331, 331, 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 // returns new coords for a point; used to test the updateData function
std::pair<double, double> advect(int time, double lat, double lon) { std::pair<double, double> advect(int time, double lat, double lon) {
return {lat+0.1, lon+0.1} ; return {lat + 0., lon + 0.};
} }
void LGlyphLayer::updateData(int t) {
// 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<double, double> 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<double, double> 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]; double point[3];
for (vtkIdType n=0; n < this->points->GetNumberOfPoints(); n++) { for (vtkIdType n = 0; n < this->points->GetNumberOfPoints(); n++) {
this->points->GetPoint(n, point); this->points->GetPoint(n, point);
auto grads = pixelToReal(point[0], point[1]); auto [xNew, yNew] = advect(n, point[0], point[1]);
auto newGrads = advect(n, grads.first, grads.second); this->points->SetPoint(n, xNew, yNew, 0);
auto newPixs = realToPixel(newGrads.first, newGrads.second);
this->points->SetPoint(n, newPixs.first, newPixs.second, 0);
} }
this->points->Modified(); this->points->Modified();
} }

View File

@ -0,0 +1,43 @@
#include "NormalisedCartographicCamera.h"
#include <vtkMatrix4x4.h>
vtkSmartPointer<vtkCamera> 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<vtkCamera> camera = vtkSmartPointer<vtkCamera>::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<vtkMatrix4x4> projectionMatrix;
projectionMatrix->DeepCopy(eyeTransform);
camera->SetExplicitProjectionTransformMatrix(projectionMatrix);
// camera->SetScreenBottomLeft(XMin, YMin, 0);
// camera->SetScreenTopRight(XMax, YMax, 0);
return camera;
}

View File

@ -0,0 +1,8 @@
#include <vtkCamera.h>
#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
#endif //VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
vtkSmartPointer<vtkCamera> createNormalisedCartographicCamera();

View File

@ -31,7 +31,14 @@ void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *ca
int x, y; int x, y;
interactor->GetEventPosition(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<double>(x), static_cast<double>(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); data->SetPoints(points);
vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New(); vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New();
@ -58,3 +65,7 @@ void SpawnPointCallback::setData(const vtkSmartPointer<vtkPolyData> &data) {
void SpawnPointCallback::setPoints(const vtkSmartPointer<vtkPoints> &points) { void SpawnPointCallback::setPoints(const vtkSmartPointer<vtkPoints> &points) {
this->points = points; this->points = points;
} }
void SpawnPointCallback::setRen(const vtkSmartPointer<vtkRenderer> &ren) {
this->ren = ren;
}

View File

@ -17,9 +17,12 @@ public:
void setData(const vtkSmartPointer<vtkPolyData> &data); void setData(const vtkSmartPointer<vtkPolyData> &data);
void setRen(const vtkSmartPointer<vtkRenderer> &ren);
private: private:
vtkSmartPointer<vtkPolyData> data; vtkSmartPointer<vtkPolyData> data;
vtkSmartPointer<vtkPoints> points; vtkSmartPointer<vtkPoints> points;
vtkSmartPointer<vtkRenderer> ren;
public: public:
private: private: