Feat: Improved organisation of Cartographic transformation

This commit is contained in:
robin 2024-05-05 16:33:45 +02:00
parent 346e44da48
commit 3356b5561a
11 changed files with 109 additions and 74 deletions

3
vtk/.gitignore vendored
View File

@ -3,4 +3,5 @@ src/.DS_Store
src/.cache
src/build
.idea
src/cmake-build-debug
src/cmake-build-debug
compile_commands.json

View File

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

View File

@ -1 +0,0 @@
build/compile_commands.json

View File

@ -0,0 +1,46 @@
#include "CartographicTransformation.h"
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
vtkSmartPointer<vtkCamera> createNormalisedCamera() {
vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
camera->ParallelProjectionOn(); // Enable parallel projection
camera->SetPosition(0, 0, 1000); // Place the camera above the center
camera->SetFocalPoint(0, 0, 0); // Look at the center
camera->SetViewUp(0, 1, 0); // Set the up vector to be along the Y-axis
camera->SetParallelScale(1); // x,y in [-1, 1]
return camera;
}
vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix() {
const double XMin = -15.875;
const double XMax = 12.875;
const double YMin = 46.125;
const double YMax = 62.625;
double eyeTransform[] = {
2/(XMax-XMin), 0, 0, -(XMax+XMin)/(XMax-XMin),
0, 2/(YMax-YMin), 0, -(YMax+YMin)/(YMax-YMin),
0, 0, 1, 0,
0, 0, 0, 1
};
auto matrix = vtkSmartPointer<vtkMatrix4x4>::New();
matrix->DeepCopy(eyeTransform);
return matrix;
}
// Assumes Normalised camera is used
vtkSmartPointer<vtkTransformFilter> createCartographicTransformFilter() {
vtkNew<vtkTransform> transform;
transform->SetMatrix(getCartographicTransformMatrix());
vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
transformFilter->SetTransform(transform);
return transformFilter;
}

View File

@ -0,0 +1,29 @@
#include <vtkCamera.h>
#include <vtkTransformFilter.h>
#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
#endif //VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
/**
* Constructs a orthographically projected camera that looks at the square x,y in [-1, 1] with z = 0 and w = 1.
* The space [-1,1] x [-1,1] x {0} will be referred to as the normalised space.
* @return pointer to camera
*/
vtkSmartPointer<vtkCamera> createNormalisedCamera();
/**
* Constructs a 4x4 projection matrix that maps homogenious (longitude, latitude, 0, 1) points
* to the normalised space.
* TODO: This transformation has room for improvement see:
* https://github.com/MakeNEnjoy/interactive-track-and-trace/issues/12
* @return pointer to 4x4 matrix
*/
vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix();
/**
* Convenience function that converts the 4x4 projection matrix into a vtkTransformFilter
* @return pointer to transform filter
*/
vtkSmartPointer<vtkTransformFilter> createCartographicTransformFilter();

View File

@ -13,7 +13,7 @@
#include <vtkVertexGlyphFilter.h>
#include <netcdf>
#include <vtkArrowSource.h>
#include "NormalisedCartographicCamera.h"
#include "CartographicTransformation.h"
using namespace netCDF;
using namespace std;
@ -65,7 +65,7 @@ void EGlyphLayer::readCoordinates() {
this->direction->SetNumberOfTuples(numLats*numLons);
points->Allocate(numLats*numLons);
auto camera = createNormalisedCartographicCamera();
auto camera = createNormalisedCamera();
ren->SetActiveCamera(camera);
int i = 0;
@ -73,7 +73,7 @@ void EGlyphLayer::readCoordinates() {
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++, lon, lat, 0); // FIXME: counts on fixed window geometry to map properly; refactor to make use of active window geometry.
points->InsertPoint(i++, lon, lat, 0);
// see also https://vtk.org/doc/nightly/html/classvtkPolyDataMapper2D.html
}
}
@ -81,6 +81,9 @@ void EGlyphLayer::readCoordinates() {
this->data->GetPointData()->AddArray(this->direction);
this->data->GetPointData()->SetActiveVectors("direction");
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
transformFilter->SetInputData(data);
vtkNew<vtkGlyphSource2D> arrowSource;
arrowSource->SetGlyphTypeToArrow();
arrowSource->SetScale(0.2); //TODO: set this properly
@ -88,7 +91,7 @@ void EGlyphLayer::readCoordinates() {
vtkNew<vtkGlyph2D> glyph2D;
glyph2D->SetSourceConnection(arrowSource->GetOutputPort());
glyph2D->SetInputData(this->data);
glyph2D->SetInputConnection(transformFilter->GetOutputPort());
glyph2D->OrientOn();
glyph2D->ClampingOn();
glyph2D->SetScaleModeToScaleByVector();

View File

@ -15,7 +15,7 @@
#include <vtkRenderWindow.h>
#include <vtkCamera.h>
#include "NormalisedCartographicCamera.h"
#include "CartographicTransformation.h"
vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
@ -42,20 +42,25 @@ LGlyphLayer::LGlyphLayer() {
this->data = vtkSmartPointer<vtkPolyData>::New();
this->data->SetPoints(this->points);
auto camera = createNormalisedCamera();
ren->SetActiveCamera(camera);
auto transform = createCartographicTransformFilter();
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
transformFilter->SetInputData(data);
vtkNew<vtkGlyphSource2D> circleSource;
circleSource->SetGlyphTypeToCircle();
circleSource->SetScale(1);
circleSource->SetScale(0.05);
circleSource->Update();
vtkNew<vtkGlyph2D> glyph2D;
glyph2D->SetSourceConnection(circleSource->GetOutputPort());
glyph2D->SetInputData(this->data);
glyph2D->SetInputConnection(transformFilter->GetOutputPort());
glyph2D->SetColorModeToColorByScalar();
glyph2D->Update();
auto camera = createNormalisedCartographicCamera();
ren->SetActiveCamera(camera);
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(glyph2D->GetOutputPort());
mapper->Update();
@ -68,13 +73,11 @@ LGlyphLayer::LGlyphLayer() {
// creates a few points so we can test the updateData function
void LGlyphLayer::spoofPoints() {
// 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->InsertNextPoint(6.532949683882039, 53.24308582564463, 0); // Coordinates of Zernike
this->points->InsertNextPoint(5.315307819255385, 60.40001057122271, 0); // Coordinates of Bergen
this->points->InsertNextPoint( 6.646210231365825, 46.52346296009023, 0); // Coordinates of Lausanne
this->points->InsertNextPoint(-6.553894313570932, 62.39522131195857, 0); // Coordinates of the top of the Faroe islands
this->points->Modified();
}

View File

@ -1,43 +0,0 @@
#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

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

View File

@ -7,6 +7,8 @@
#include <vtkCommand.h>
#include <vtkRenderWindow.h>
#include "CartographicTransformation.h"
void convertDisplayToWorld(vtkRenderer* renderer, int x, int y, double *worldPos) {
double displayPos[3] = {static_cast<double>(x), static_cast<double>(y), 0.0};
renderer->SetDisplayPoint(displayPos);
@ -36,6 +38,7 @@ void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *ca
ren->SetDisplayPoint(displayPos);
ren->DisplayToWorld();
ren->GetWorldPoint(worldPos);
inverseCartographicProjection->MultiplyPoint(worldPos, worldPos);
cout << "clicked on lon = " << worldPos[0] << " and lat = " << worldPos[1] << endl;
vtkIdType id = points->InsertNextPoint(worldPos[0], worldPos[1], 0);
@ -52,7 +55,10 @@ void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *ca
}
SpawnPointCallback::SpawnPointCallback() : data(nullptr), points(nullptr) {}
SpawnPointCallback::SpawnPointCallback() : data(nullptr), points(nullptr), inverseCartographicProjection(nullptr) {
inverseCartographicProjection = getCartographicTransformMatrix();
inverseCartographicProjection->Invert();
}
SpawnPointCallback *SpawnPointCallback::New() {
return new SpawnPointCallback;

View File

@ -6,6 +6,7 @@
#include <vtkRenderWindowInteractor.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkMatrix4x4.h>
class SpawnPointCallback : public vtkCallbackCommand {
@ -18,14 +19,12 @@ public:
void setData(const vtkSmartPointer<vtkPolyData> &data);
void setRen(const vtkSmartPointer<vtkRenderer> &ren);
private:
vtkSmartPointer<vtkPolyData> data;
vtkSmartPointer<vtkPoints> points;
vtkSmartPointer<vtkRenderer> ren;
public:
vtkSmartPointer<vtkMatrix4x4> inverseCartographicProjection;
private:
void Execute(vtkObject *caller, unsigned long evId, void *callData) override;
bool dragging = false;
};