Feat: Improved organisation of Cartographic transformation
This commit is contained in:
parent
346e44da48
commit
3356b5561a
|
|
@ -3,4 +3,5 @@ src/.DS_Store
|
||||||
src/.cache
|
src/.cache
|
||||||
src/build
|
src/build
|
||||||
.idea
|
.idea
|
||||||
src/cmake-build-debug
|
src/cmake-build-debug
|
||||||
|
compile_commands.json
|
||||||
|
|
@ -46,7 +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
|
helperClasses/CartographicTransformation.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
build/compile_commands.json
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
#include <vtkVertexGlyphFilter.h>
|
#include <vtkVertexGlyphFilter.h>
|
||||||
#include <netcdf>
|
#include <netcdf>
|
||||||
#include <vtkArrowSource.h>
|
#include <vtkArrowSource.h>
|
||||||
#include "NormalisedCartographicCamera.h"
|
#include "CartographicTransformation.h"
|
||||||
|
|
||||||
using namespace netCDF;
|
using namespace netCDF;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
@ -65,7 +65,7 @@ void EGlyphLayer::readCoordinates() {
|
||||||
this->direction->SetNumberOfTuples(numLats*numLons);
|
this->direction->SetNumberOfTuples(numLats*numLons);
|
||||||
points->Allocate(numLats*numLons);
|
points->Allocate(numLats*numLons);
|
||||||
|
|
||||||
auto camera = createNormalisedCartographicCamera();
|
auto camera = createNormalisedCamera();
|
||||||
ren->SetActiveCamera(camera);
|
ren->SetActiveCamera(camera);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
@ -73,7 +73,7 @@ void EGlyphLayer::readCoordinates() {
|
||||||
for (double lon : lons) {
|
for (double lon : lons) {
|
||||||
cout << "lon: " << lon << " lat: " << lat << endl;
|
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++, 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
|
// 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()->AddArray(this->direction);
|
||||||
this->data->GetPointData()->SetActiveVectors("direction");
|
this->data->GetPointData()->SetActiveVectors("direction");
|
||||||
|
|
||||||
|
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
||||||
|
transformFilter->SetInputData(data);
|
||||||
|
|
||||||
vtkNew<vtkGlyphSource2D> arrowSource;
|
vtkNew<vtkGlyphSource2D> arrowSource;
|
||||||
arrowSource->SetGlyphTypeToArrow();
|
arrowSource->SetGlyphTypeToArrow();
|
||||||
arrowSource->SetScale(0.2); //TODO: set this properly
|
arrowSource->SetScale(0.2); //TODO: set this properly
|
||||||
|
|
@ -88,7 +91,7 @@ void EGlyphLayer::readCoordinates() {
|
||||||
|
|
||||||
vtkNew<vtkGlyph2D> glyph2D;
|
vtkNew<vtkGlyph2D> glyph2D;
|
||||||
glyph2D->SetSourceConnection(arrowSource->GetOutputPort());
|
glyph2D->SetSourceConnection(arrowSource->GetOutputPort());
|
||||||
glyph2D->SetInputData(this->data);
|
glyph2D->SetInputConnection(transformFilter->GetOutputPort());
|
||||||
glyph2D->OrientOn();
|
glyph2D->OrientOn();
|
||||||
glyph2D->ClampingOn();
|
glyph2D->ClampingOn();
|
||||||
glyph2D->SetScaleModeToScaleByVector();
|
glyph2D->SetScaleModeToScaleByVector();
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
#include <vtkRenderWindow.h>
|
#include <vtkRenderWindow.h>
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
|
|
||||||
#include "NormalisedCartographicCamera.h"
|
#include "CartographicTransformation.h"
|
||||||
|
|
||||||
|
|
||||||
vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
|
vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
|
||||||
|
|
@ -42,20 +42,25 @@ LGlyphLayer::LGlyphLayer() {
|
||||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||||
this->data->SetPoints(this->points);
|
this->data->SetPoints(this->points);
|
||||||
|
|
||||||
|
auto camera = createNormalisedCamera();
|
||||||
|
ren->SetActiveCamera(camera);
|
||||||
|
|
||||||
|
auto transform = createCartographicTransformFilter();
|
||||||
|
|
||||||
|
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
||||||
|
transformFilter->SetInputData(data);
|
||||||
|
|
||||||
vtkNew<vtkGlyphSource2D> circleSource;
|
vtkNew<vtkGlyphSource2D> circleSource;
|
||||||
circleSource->SetGlyphTypeToCircle();
|
circleSource->SetGlyphTypeToCircle();
|
||||||
circleSource->SetScale(1);
|
circleSource->SetScale(0.05);
|
||||||
circleSource->Update();
|
circleSource->Update();
|
||||||
|
|
||||||
vtkNew<vtkGlyph2D> glyph2D;
|
vtkNew<vtkGlyph2D> glyph2D;
|
||||||
glyph2D->SetSourceConnection(circleSource->GetOutputPort());
|
glyph2D->SetSourceConnection(circleSource->GetOutputPort());
|
||||||
glyph2D->SetInputData(this->data);
|
glyph2D->SetInputConnection(transformFilter->GetOutputPort());
|
||||||
glyph2D->SetColorModeToColorByScalar();
|
glyph2D->SetColorModeToColorByScalar();
|
||||||
glyph2D->Update();
|
glyph2D->Update();
|
||||||
|
|
||||||
auto camera = createNormalisedCartographicCamera();
|
|
||||||
ren->SetActiveCamera(camera);
|
|
||||||
|
|
||||||
vtkNew<vtkPolyDataMapper> mapper;
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
mapper->SetInputConnection(glyph2D->GetOutputPort());
|
mapper->SetInputConnection(glyph2D->GetOutputPort());
|
||||||
mapper->Update();
|
mapper->Update();
|
||||||
|
|
@ -68,13 +73,11 @@ LGlyphLayer::LGlyphLayer() {
|
||||||
|
|
||||||
// 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(200, 200 , 0);
|
|
||||||
this->points->InsertNextPoint(-4.125, 61.375 , 0);
|
this->points->InsertNextPoint(-4.125, 61.375 , 0);
|
||||||
this->points->InsertNextPoint(4.896555178870355, 52.373557841669516, 0);
|
this->points->InsertNextPoint(6.532949683882039, 53.24308582564463, 0); // Coordinates of Zernike
|
||||||
// this->points->InsertNextPoint(48.2, 111.01, 0);
|
this->points->InsertNextPoint(5.315307819255385, 60.40001057122271, 0); // Coordinates of Bergen
|
||||||
// this->points->InsertNextPoint(331, 331, 0);
|
this->points->InsertNextPoint( 6.646210231365825, 46.52346296009023, 0); // Coordinates of Lausanne
|
||||||
// this->points->InsertNextPoint(0, 50, 0);
|
this->points->InsertNextPoint(-6.553894313570932, 62.39522131195857, 0); // Coordinates of the top of the Faroe islands
|
||||||
// this->points->InsertNextPoint(200, 200 , 0);
|
|
||||||
|
|
||||||
this->points->Modified();
|
this->points->Modified();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#include <vtkCamera.h>
|
|
||||||
|
|
||||||
#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
|
||||||
#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
|
||||||
|
|
||||||
#endif //VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
|
||||||
|
|
||||||
vtkSmartPointer<vtkCamera> createNormalisedCartographicCamera();
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
#include <vtkCommand.h>
|
#include <vtkCommand.h>
|
||||||
#include <vtkRenderWindow.h>
|
#include <vtkRenderWindow.h>
|
||||||
|
|
||||||
|
#include "CartographicTransformation.h"
|
||||||
|
|
||||||
void convertDisplayToWorld(vtkRenderer* renderer, int x, int y, double *worldPos) {
|
void convertDisplayToWorld(vtkRenderer* renderer, int x, int y, double *worldPos) {
|
||||||
double displayPos[3] = {static_cast<double>(x), static_cast<double>(y), 0.0};
|
double displayPos[3] = {static_cast<double>(x), static_cast<double>(y), 0.0};
|
||||||
renderer->SetDisplayPoint(displayPos);
|
renderer->SetDisplayPoint(displayPos);
|
||||||
|
|
@ -36,6 +38,7 @@ void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *ca
|
||||||
ren->SetDisplayPoint(displayPos);
|
ren->SetDisplayPoint(displayPos);
|
||||||
ren->DisplayToWorld();
|
ren->DisplayToWorld();
|
||||||
ren->GetWorldPoint(worldPos);
|
ren->GetWorldPoint(worldPos);
|
||||||
|
inverseCartographicProjection->MultiplyPoint(worldPos, worldPos);
|
||||||
cout << "clicked on lon = " << worldPos[0] << " and lat = " << worldPos[1] << endl;
|
cout << "clicked on lon = " << worldPos[0] << " and lat = " << worldPos[1] << endl;
|
||||||
|
|
||||||
vtkIdType id = points->InsertNextPoint(worldPos[0], worldPos[1], 0);
|
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() {
|
SpawnPointCallback *SpawnPointCallback::New() {
|
||||||
return new SpawnPointCallback;
|
return new SpawnPointCallback;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <vtkRenderWindowInteractor.h>
|
#include <vtkRenderWindowInteractor.h>
|
||||||
#include <vtkPoints.h>
|
#include <vtkPoints.h>
|
||||||
#include <vtkPolyData.h>
|
#include <vtkPolyData.h>
|
||||||
|
#include <vtkMatrix4x4.h>
|
||||||
|
|
||||||
class SpawnPointCallback : public vtkCallbackCommand {
|
class SpawnPointCallback : public vtkCallbackCommand {
|
||||||
|
|
||||||
|
|
@ -18,14 +19,12 @@ public:
|
||||||
void setData(const vtkSmartPointer<vtkPolyData> &data);
|
void setData(const vtkSmartPointer<vtkPolyData> &data);
|
||||||
|
|
||||||
void setRen(const vtkSmartPointer<vtkRenderer> &ren);
|
void setRen(const vtkSmartPointer<vtkRenderer> &ren);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vtkSmartPointer<vtkPolyData> data;
|
vtkSmartPointer<vtkPolyData> data;
|
||||||
vtkSmartPointer<vtkPoints> points;
|
vtkSmartPointer<vtkPoints> points;
|
||||||
vtkSmartPointer<vtkRenderer> ren;
|
vtkSmartPointer<vtkRenderer> ren;
|
||||||
public:
|
vtkSmartPointer<vtkMatrix4x4> inverseCartographicProjection;
|
||||||
|
|
||||||
private:
|
|
||||||
void Execute(vtkObject *caller, unsigned long evId, void *callData) override;
|
void Execute(vtkObject *caller, unsigned long evId, void *callData) override;
|
||||||
bool dragging = false;
|
bool dragging = false;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue