normalised cartographic camera
This commit is contained in:
parent
06315a3d52
commit
346e44da48
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <vtkVertexGlyphFilter.h>
|
||||
#include <netcdf>
|
||||
#include <vtkArrowSource.h>
|
||||
#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<vtkGlyphSource2D> arrowSource;
|
||||
arrowSource->SetGlyphTypeToArrow();
|
||||
arrowSource->SetScale(8); //TODO: set this properly
|
||||
arrowSource->SetScale(0.2); //TODO: set this properly
|
||||
arrowSource->Update();
|
||||
|
||||
vtkNew<vtkGlyph2D> glyph2D;
|
||||
|
|
@ -90,15 +95,15 @@ void EGlyphLayer::readCoordinates() {
|
|||
glyph2D->SetVectorModeToUseVector();
|
||||
glyph2D->Update();
|
||||
|
||||
vtkNew<vtkCoordinate> coordinate;
|
||||
coordinate->SetCoordinateSystemToWorld();
|
||||
// vtkNew<vtkCoordinate> coordinate;
|
||||
// coordinate->SetCoordinateSystemToWorld();
|
||||
|
||||
vtkNew<vtkPolyDataMapper2D>(mapper);
|
||||
vtkNew<vtkPolyDataMapper>(mapper);
|
||||
// mapper->SetTransformCoordinate(coordinate);
|
||||
mapper->SetInputConnection(glyph2D->GetOutputPort());
|
||||
mapper->Update();
|
||||
|
||||
vtkNew<vtkActor2D> actor;
|
||||
vtkNew<vtkActor> actor;
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
actor->GetProperty()->SetColor(0,0,0);
|
||||
|
|
|
|||
|
|
@ -9,16 +9,23 @@
|
|||
#include <vtkVertexGlyphFilter.h>
|
||||
#include <vtkInteractorStyle.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() {
|
||||
auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::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<SpawnPointCallback> 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<vtkRenderer>::New();
|
||||
this->ren->SetLayer(2);
|
||||
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
||||
this->ren->SetLayer(2);
|
||||
|
||||
this->points = vtkSmartPointer<vtkPoints>::New();
|
||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||
this->data->SetPoints(this->points);
|
||||
|
||||
vtkNew<vtkGlyphSource2D> circleSource;
|
||||
circleSource->SetGlyphTypeToCircle();
|
||||
circleSource->SetScale(15);
|
||||
circleSource->Update();
|
||||
this->points = vtkSmartPointer<vtkPoints>::New();
|
||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||
this->data->SetPoints(this->points);
|
||||
|
||||
vtkNew<vtkGlyph2D> glyph2D;
|
||||
glyph2D->SetSourceConnection(circleSource->GetOutputPort());
|
||||
glyph2D->SetInputData(this->data);
|
||||
glyph2D->SetColorModeToColorByScalar();
|
||||
glyph2D->Update();
|
||||
vtkNew<vtkGlyphSource2D> circleSource;
|
||||
circleSource->SetGlyphTypeToCircle();
|
||||
circleSource->SetScale(1);
|
||||
circleSource->Update();
|
||||
|
||||
vtkNew<vtkPolyDataMapper2D> mapper;
|
||||
mapper->SetInputConnection(glyph2D->GetOutputPort());
|
||||
mapper->Update();
|
||||
vtkNew<vtkGlyph2D> glyph2D;
|
||||
glyph2D->SetSourceConnection(circleSource->GetOutputPort());
|
||||
glyph2D->SetInputData(this->data);
|
||||
glyph2D->SetColorModeToColorByScalar();
|
||||
glyph2D->Update();
|
||||
|
||||
vtkNew<vtkActor2D> actor;
|
||||
actor->SetMapper(mapper);
|
||||
actor->GetProperty()->SetColor(1,1,1);
|
||||
auto camera = createNormalisedCartographicCamera();
|
||||
ren->SetActiveCamera(camera);
|
||||
|
||||
this->ren->AddActor(actor);
|
||||
vtkNew<vtkPolyDataMapper> mapper;
|
||||
mapper->SetInputConnection(glyph2D->GetOutputPort());
|
||||
mapper->Update();
|
||||
|
||||
vtkNew<vtkActor> 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<double, double> 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<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];
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#include <vtkCamera.h>
|
||||
|
||||
#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
||||
#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
||||
|
||||
#endif //VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
||||
|
||||
vtkSmartPointer<vtkCamera> createNormalisedCartographicCamera();
|
||||
|
|
@ -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<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);
|
||||
|
||||
vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New();
|
||||
|
|
@ -57,4 +64,8 @@ void SpawnPointCallback::setData(const vtkSmartPointer<vtkPolyData> &data) {
|
|||
|
||||
void SpawnPointCallback::setPoints(const vtkSmartPointer<vtkPoints> &points) {
|
||||
this->points = points;
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnPointCallback::setRen(const vtkSmartPointer<vtkRenderer> &ren) {
|
||||
this->ren = ren;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,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:
|
||||
|
||||
private:
|
||||
|
|
|
|||
Loading…
Reference in New Issue