diff --git a/vtk/.gitignore b/vtk/.gitignore index 95abd3d..ea37cb8 100644 --- a/vtk/.gitignore +++ b/vtk/.gitignore @@ -3,4 +3,5 @@ src/.DS_Store src/.cache src/build .idea -src/cmake-build-debug \ No newline at end of file +src/cmake-build-debug +compile_commands.json \ No newline at end of file diff --git a/vtk/src/CMakeLists.txt b/vtk/src/CMakeLists.txt index 9cb04bc..cb39085 100644 --- a/vtk/src/CMakeLists.txt +++ b/vtk/src/CMakeLists.txt @@ -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( diff --git a/vtk/src/compile_commands.json b/vtk/src/compile_commands.json deleted file mode 120000 index 25eb4b2..0000000 --- a/vtk/src/compile_commands.json +++ /dev/null @@ -1 +0,0 @@ -build/compile_commands.json \ No newline at end of file diff --git a/vtk/src/helperClasses/CartographicTransformation.cpp b/vtk/src/helperClasses/CartographicTransformation.cpp new file mode 100644 index 0000000..54c528e --- /dev/null +++ b/vtk/src/helperClasses/CartographicTransformation.cpp @@ -0,0 +1,46 @@ +#include "CartographicTransformation.h" +#include +#include +#include + +vtkSmartPointer createNormalisedCamera() { + vtkSmartPointer camera = vtkSmartPointer::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 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::New(); + matrix->DeepCopy(eyeTransform); + return matrix; +} + +// Assumes Normalised camera is used +vtkSmartPointer createCartographicTransformFilter() { + vtkNew transform; + + transform->SetMatrix(getCartographicTransformMatrix()); + + vtkSmartPointer transformFilter = vtkSmartPointer::New(); + transformFilter->SetTransform(transform); + + return transformFilter; +} diff --git a/vtk/src/helperClasses/CartographicTransformation.h b/vtk/src/helperClasses/CartographicTransformation.h new file mode 100644 index 0000000..368483d --- /dev/null +++ b/vtk/src/helperClasses/CartographicTransformation.h @@ -0,0 +1,29 @@ +#include +#include + +#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 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 getCartographicTransformMatrix(); + +/** + * Convenience function that converts the 4x4 projection matrix into a vtkTransformFilter + * @return pointer to transform filter + */ +vtkSmartPointer createCartographicTransformFilter(); \ No newline at end of file diff --git a/vtk/src/helperClasses/EGlyphLayer.cpp b/vtk/src/helperClasses/EGlyphLayer.cpp index 4d3265d..0722a34 100644 --- a/vtk/src/helperClasses/EGlyphLayer.cpp +++ b/vtk/src/helperClasses/EGlyphLayer.cpp @@ -13,7 +13,7 @@ #include #include #include -#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 transformFilter = createCartographicTransformFilter(); + transformFilter->SetInputData(data); + vtkNew arrowSource; arrowSource->SetGlyphTypeToArrow(); arrowSource->SetScale(0.2); //TODO: set this properly @@ -88,7 +91,7 @@ void EGlyphLayer::readCoordinates() { vtkNew glyph2D; glyph2D->SetSourceConnection(arrowSource->GetOutputPort()); - glyph2D->SetInputData(this->data); + glyph2D->SetInputConnection(transformFilter->GetOutputPort()); glyph2D->OrientOn(); glyph2D->ClampingOn(); glyph2D->SetScaleModeToScaleByVector(); diff --git a/vtk/src/helperClasses/LGlyphLayer.cpp b/vtk/src/helperClasses/LGlyphLayer.cpp index 00e3ef5..3b1a051 100644 --- a/vtk/src/helperClasses/LGlyphLayer.cpp +++ b/vtk/src/helperClasses/LGlyphLayer.cpp @@ -15,7 +15,7 @@ #include #include -#include "NormalisedCartographicCamera.h" +#include "CartographicTransformation.h" vtkSmartPointer LGlyphLayer::createSpawnPointCallback() { @@ -42,20 +42,25 @@ LGlyphLayer::LGlyphLayer() { this->data = vtkSmartPointer::New(); this->data->SetPoints(this->points); + auto camera = createNormalisedCamera(); + ren->SetActiveCamera(camera); + + auto transform = createCartographicTransformFilter(); + + vtkSmartPointer transformFilter = createCartographicTransformFilter(); + transformFilter->SetInputData(data); + vtkNew circleSource; circleSource->SetGlyphTypeToCircle(); - circleSource->SetScale(1); + circleSource->SetScale(0.05); circleSource->Update(); vtkNew glyph2D; glyph2D->SetSourceConnection(circleSource->GetOutputPort()); - glyph2D->SetInputData(this->data); + glyph2D->SetInputConnection(transformFilter->GetOutputPort()); glyph2D->SetColorModeToColorByScalar(); glyph2D->Update(); - auto camera = createNormalisedCartographicCamera(); - ren->SetActiveCamera(camera); - vtkNew 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(); } diff --git a/vtk/src/helperClasses/NormalisedCartographicCamera.cpp b/vtk/src/helperClasses/NormalisedCartographicCamera.cpp deleted file mode 100644 index d34bafe..0000000 --- a/vtk/src/helperClasses/NormalisedCartographicCamera.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#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 deleted file mode 100644 index fca5a39..0000000 --- a/vtk/src/helperClasses/NormalisedCartographicCamera.h +++ /dev/null @@ -1,8 +0,0 @@ -#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 15eca3b..e52b88f 100644 --- a/vtk/src/helperClasses/SpawnPointCallback.cpp +++ b/vtk/src/helperClasses/SpawnPointCallback.cpp @@ -7,6 +7,8 @@ #include #include +#include "CartographicTransformation.h" + void convertDisplayToWorld(vtkRenderer* renderer, int x, int y, double *worldPos) { double displayPos[3] = {static_cast(x), static_cast(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; diff --git a/vtk/src/helperClasses/SpawnPointCallback.h b/vtk/src/helperClasses/SpawnPointCallback.h index e71063d..bef6ca4 100644 --- a/vtk/src/helperClasses/SpawnPointCallback.h +++ b/vtk/src/helperClasses/SpawnPointCallback.h @@ -6,6 +6,7 @@ #include #include #include +#include class SpawnPointCallback : public vtkCallbackCommand { @@ -18,14 +19,12 @@ public: void setData(const vtkSmartPointer &data); void setRen(const vtkSmartPointer &ren); - private: vtkSmartPointer data; vtkSmartPointer points; vtkSmartPointer ren; -public: + vtkSmartPointer inverseCartographicProjection; -private: void Execute(vtkObject *caller, unsigned long evId, void *callData) override; bool dragging = false; };