fix: unified dt
This commit is contained in:
parent
705cf248cb
commit
09a285e41c
|
|
@ -15,11 +15,11 @@ vtkSmartPointer<vtkCamera> createNormalisedCamera() {
|
||||||
return camera;
|
return camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix() {
|
vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix(const std::shared_ptr<UVGrid> uvGrid) {
|
||||||
const double XMin = -15.875;
|
const double XMin = uvGrid->lons.front();
|
||||||
const double XMax = 12.875;
|
const double XMax = uvGrid->lons.back();
|
||||||
const double YMin = 46.125;
|
const double YMin = uvGrid->lats.front();
|
||||||
const double YMax = 62.625;
|
const double YMax = uvGrid->lats.back();
|
||||||
|
|
||||||
double eyeTransform[] = {
|
double eyeTransform[] = {
|
||||||
2/(XMax-XMin), 0, 0, -(XMax+XMin)/(XMax-XMin),
|
2/(XMax-XMin), 0, 0, -(XMax+XMin)/(XMax-XMin),
|
||||||
|
|
@ -34,10 +34,10 @@ vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes Normalised camera is used
|
// Assumes Normalised camera is used
|
||||||
vtkSmartPointer<vtkTransformFilter> createCartographicTransformFilter() {
|
vtkSmartPointer<vtkTransformFilter> createCartographicTransformFilter(const std::shared_ptr<UVGrid> uvGrid) {
|
||||||
vtkNew<vtkTransform> transform;
|
vtkNew<vtkTransform> transform;
|
||||||
|
|
||||||
transform->SetMatrix(getCartographicTransformMatrix());
|
transform->SetMatrix(getCartographicTransformMatrix(uvGrid));
|
||||||
|
|
||||||
vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
|
vtkSmartPointer<vtkTransformFilter> transformFilter = vtkSmartPointer<vtkTransformFilter>::New();
|
||||||
transformFilter->SetTransform(transform);
|
transformFilter->SetTransform(transform);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
#include <vtkTransformFilter.h>
|
#include <vtkTransformFilter.h>
|
||||||
|
#include "advection/UVGrid.h"
|
||||||
|
|
||||||
#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
#ifndef VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
||||||
#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
#define VTKBASE_NORMALISEDCARTOGRAPHICCAMERA_H
|
||||||
|
|
@ -16,15 +17,14 @@ vtkSmartPointer<vtkCamera> createNormalisedCamera();
|
||||||
/**
|
/**
|
||||||
* Constructs a 4x4 projection matrix that maps homogenious (longitude, latitude, 0, 1) points
|
* Constructs a 4x4 projection matrix that maps homogenious (longitude, latitude, 0, 1) points
|
||||||
* to the normalised space.
|
* to the normalised space.
|
||||||
* TODO: This will soon require UVGrid as a parameter after the advection code is merged properly.
|
|
||||||
* TODO: This transformation has room for improvement see:
|
* TODO: This transformation has room for improvement see:
|
||||||
* https://github.com/MakeNEnjoy/interactive-track-and-trace/issues/12
|
* https://github.com/MakeNEnjoy/interactive-track-and-trace/issues/12
|
||||||
* @return pointer to 4x4 matrix
|
* @return pointer to 4x4 matrix
|
||||||
*/
|
*/
|
||||||
vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix();
|
vtkSmartPointer<vtkMatrix4x4> getCartographicTransformMatrix(const std::shared_ptr<UVGrid> uvGrid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function that converts the 4x4 projection matrix into a vtkTransformFilter
|
* Convenience function that converts the 4x4 projection matrix into a vtkTransformFilter
|
||||||
* @return pointer to transform filter
|
* @return pointer to transform filter
|
||||||
*/
|
*/
|
||||||
vtkSmartPointer<vtkTransformFilter> createCartographicTransformFilter();
|
vtkSmartPointer<vtkTransformFilter> createCartographicTransformFilter(const std::shared_ptr<UVGrid> uvGrid);
|
||||||
|
|
@ -33,21 +33,22 @@ void Program::setWinProperties() {
|
||||||
interact->SetInteractorStyle(style);
|
interact->SetInteractorStyle(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Program::setupTimer() {
|
void Program::setupTimer(int dt) {
|
||||||
auto callback = vtkSmartPointer<TimerCallbackCommand>::New(this);
|
auto callback = vtkSmartPointer<TimerCallbackCommand>::New(this);
|
||||||
callback->SetClientData(this);
|
callback->SetClientData(this);
|
||||||
|
callback->setDt(dt);
|
||||||
this->interact->AddObserver(vtkCommand::TimerEvent, callback);
|
this->interact->AddObserver(vtkCommand::TimerEvent, callback);
|
||||||
this->interact->AddObserver(vtkCommand::KeyPressEvent, callback);
|
this->interact->AddObserver(vtkCommand::KeyPressEvent, callback);
|
||||||
this->interact->CreateRepeatingTimer(17); // 60 fps == 1000 / 60 == 16.7 ms per frame
|
this->interact->CreateRepeatingTimer(17); // 60 fps == 1000 / 60 == 16.7 ms per frame
|
||||||
}
|
}
|
||||||
|
|
||||||
Program::Program() {
|
Program::Program(int timerDT) {
|
||||||
this->win = vtkSmartPointer<vtkRenderWindow>::New();
|
this->win = vtkSmartPointer<vtkRenderWindow>::New();
|
||||||
this->interact = vtkSmartPointer<vtkRenderWindowInteractor>::New();
|
this->interact = vtkSmartPointer<vtkRenderWindowInteractor>::New();
|
||||||
|
|
||||||
this->win->SetNumberOfLayers(0);
|
this->win->SetNumberOfLayers(0);
|
||||||
setWinProperties();
|
setWinProperties();
|
||||||
setupTimer();
|
setupTimer(timerDT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,14 @@ private:
|
||||||
|
|
||||||
/** This function sets up and connects a TimerCallbackCommand with the program.
|
/** This function sets up and connects a TimerCallbackCommand with the program.
|
||||||
*/
|
*/
|
||||||
void setupTimer();
|
void setupTimer(int dt);
|
||||||
|
|
||||||
void setupInteractions();
|
void setupInteractions();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
*/
|
*/
|
||||||
Program();
|
Program(int timerDT);
|
||||||
|
|
||||||
/** This function adds a new layer (and thus vtkRenderer) to the program.
|
/** This function adds a new layer (and thus vtkRenderer) to the program.
|
||||||
* The layer is expected to set its own position in the vtkRenderWindow layer system.
|
* The layer is expected to set its own position in the vtkRenderWindow layer system.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
*/
|
*/
|
||||||
class AdvectionKernel {
|
class AdvectionKernel {
|
||||||
public:
|
public:
|
||||||
const static int DT = 15 * 60 * 15; // 60 sec/min * 15 mins
|
|
||||||
/**
|
/**
|
||||||
* This function must take a time, latitude and longitude of a particle and must output
|
* This function must take a time, latitude and longitude of a particle and must output
|
||||||
* a new latitude and longitude after being advected once for AdvectionKernel::DT time as defined above.
|
* a new latitude and longitude after being advected once for AdvectionKernel::DT time as defined above.
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
EulerAdvectionKernel::EulerAdvectionKernel(std::shared_ptr<UVGrid> grid): grid(grid) { }
|
EulerAdvectionKernel::EulerAdvectionKernel(std::shared_ptr<UVGrid> grid, int dt) : grid(grid), dt(dt) {}
|
||||||
|
|
||||||
std::pair<double, double> EulerAdvectionKernel::advect(int time, double latitude, double longitude) const {
|
std::pair<double, double> EulerAdvectionKernel::advect(int time, double latitude, double longitude) const {
|
||||||
auto [u, v] = bilinearinterpolate(*grid, time, latitude, longitude);
|
auto [u, v] = bilinearinterpolate(*grid, time, latitude, longitude);
|
||||||
|
|
||||||
return {latitude+metreToDegrees(v*DT), longitude+metreToDegrees(u*DT)};
|
return {latitude + metreToDegrees(v * dt), longitude + metreToDegrees(u * dt)};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,9 @@
|
||||||
class EulerAdvectionKernel: public AdvectionKernel {
|
class EulerAdvectionKernel: public AdvectionKernel {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<UVGrid> grid;
|
std::shared_ptr<UVGrid> grid;
|
||||||
|
int dt;
|
||||||
public:
|
public:
|
||||||
explicit EulerAdvectionKernel(std::shared_ptr<UVGrid> grid);
|
explicit EulerAdvectionKernel(std::shared_ptr<UVGrid> grid, int dt);
|
||||||
std::pair<double, double> advect(int time, double latitude, double longitude) const override;
|
std::pair<double, double> advect(int time, double latitude, double longitude) const override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,33 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
RK4AdvectionKernel::RK4AdvectionKernel(std::shared_ptr<UVGrid> grid): grid(grid) { }
|
RK4AdvectionKernel::RK4AdvectionKernel(std::shared_ptr<UVGrid> grid, int dt): grid(grid), dt(dt) { }
|
||||||
|
|
||||||
std::pair<double, double> RK4AdvectionKernel::advect(int time, double latitude, double longitude) const {
|
std::pair<double, double> RK4AdvectionKernel::advect(int time, double latitude, double longitude) const {
|
||||||
auto [u1, v1] = bilinearinterpolate(*grid, time, latitude, longitude);
|
auto [u1, v1] = bilinearinterpolate(*grid, time, latitude, longitude);
|
||||||
// lon1, lat1 = (particle.lon + u1*.5*particle.dt, particle.lat + v1*.5*particle.dt);
|
// lon1, lat1 = (particle.lon + u1*.5*particle.dt, particle.lat + v1*.5*particle.dt);
|
||||||
double lon1 = longitude + metreToDegrees(u1 * 0.5*DT);
|
double lon1 = longitude + metreToDegrees(u1 * 0.5*dt);
|
||||||
double lat1 = latitude + metreToDegrees(v1 * 0.5*DT);
|
double lat1 = latitude + metreToDegrees(v1 * 0.5*dt);
|
||||||
|
|
||||||
// (u2, v2) = fieldset.UV[time + .5 * particle.dt, particle.depth, lat1, lon1, particle]
|
// (u2, v2) = fieldset.UV[time + .5 * particle.dt, particle.depth, lat1, lon1, particle]
|
||||||
auto [u2, v2] = bilinearinterpolate(*grid, time + 0.5 * DT, lat1, lon1);
|
auto [u2, v2] = bilinearinterpolate(*grid, time + 0.5 * dt, lat1, lon1);
|
||||||
|
|
||||||
// lon2, lat2 = (particle.lon + u2*.5*particle.dt, particle.lat + v2*.5*particle.dt)
|
// lon2, lat2 = (particle.lon + u2*.5*particle.dt, particle.lat + v2*.5*particle.dt)
|
||||||
double lon2 = longitude + metreToDegrees(u2 * 0.5 * DT);
|
double lon2 = longitude + metreToDegrees(u2 * 0.5 * dt);
|
||||||
double lat2 = latitude + metreToDegrees(v2 * 0.5 * DT);
|
double lat2 = latitude + metreToDegrees(v2 * 0.5 * dt);
|
||||||
|
|
||||||
// (u3, v3) = fieldset.UV[time + .5 * particle.dt, particle.depth, lat2, lon2, particle]
|
// (u3, v3) = fieldset.UV[time + .5 * particle.dt, particle.depth, lat2, lon2, particle]
|
||||||
auto [u3, v3] = bilinearinterpolate(*grid, time + 0.5 * DT, lat2, lon2);
|
auto [u3, v3] = bilinearinterpolate(*grid, time + 0.5 * dt, lat2, lon2);
|
||||||
|
|
||||||
// lon3, lat3 = (particle.lon + u3*particle.dt, particle.lat + v3*particle.dt)
|
// lon3, lat3 = (particle.lon + u3*particle.dt, particle.lat + v3*particle.dt)
|
||||||
double lon3 = longitude + metreToDegrees(u3 * DT);
|
double lon3 = longitude + metreToDegrees(u3 * dt);
|
||||||
double lat3 = latitude + metreToDegrees(v3 * DT);
|
double lat3 = latitude + metreToDegrees(v3 * dt);
|
||||||
|
|
||||||
// (u4, v4) = fieldset.UV[time + particle.dt, particle.depth, lat3, lon3, particle]
|
// (u4, v4) = fieldset.UV[time + particle.dt, particle.depth, lat3, lon3, particle]
|
||||||
auto [u4, v4] = bilinearinterpolate(*grid, time + DT, lat3, lon3);
|
auto [u4, v4] = bilinearinterpolate(*grid, time + dt, lat3, lon3);
|
||||||
|
|
||||||
double lonFinal = longitude + metreToDegrees((u1 + 2 * u2 + 2 * u3 + u4) / 6.0 * DT);
|
double lonFinal = longitude + metreToDegrees((u1 + 2 * u2 + 2 * u3 + u4) / 6.0 * dt);
|
||||||
double latFinal = latitude + metreToDegrees((v1 + 2 * v2 + 2 * v3 + v4) / 6.0 * DT);
|
double latFinal = latitude + metreToDegrees((v1 + 2 * v2 + 2 * v3 + v4) / 6.0 * dt);
|
||||||
|
|
||||||
return {latFinal, lonFinal};
|
return {latFinal, lonFinal};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@
|
||||||
class RK4AdvectionKernel: public AdvectionKernel {
|
class RK4AdvectionKernel: public AdvectionKernel {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<UVGrid> grid;
|
std::shared_ptr<UVGrid> grid;
|
||||||
|
int dt;
|
||||||
public:
|
public:
|
||||||
explicit RK4AdvectionKernel(std::shared_ptr<UVGrid> grid);
|
explicit RK4AdvectionKernel(std::shared_ptr<UVGrid> grid, int dt);
|
||||||
std::pair<double, double> advect(int time, double latitude, double longitude) const override;
|
std::pair<double, double> advect(int time, double latitude, double longitude) const override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
#include <ranges>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "interpolate.h"
|
|
||||||
#include "Vel.h"
|
|
||||||
#include "EulerAdvectionKernel.h"
|
|
||||||
#include "RK4AdvectionKernel.h"
|
|
||||||
#include "interpolate.h"
|
|
||||||
|
|
||||||
#define NotAKernelError "Template parameter T must derive from AdvectionKernel"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
template <typename AdvectionKernelImpl>
|
|
||||||
void advectForSomeTime(const UVGrid &uvGrid, const AdvectionKernelImpl &kernel, double latstart, double lonstart, int i, char colour[10]) {
|
|
||||||
|
|
||||||
// Require at compile time that kernel derives from the abstract class AdvectionKernel
|
|
||||||
static_assert(std::is_base_of<AdvectionKernel, AdvectionKernelImpl>::value, NotAKernelError);
|
|
||||||
|
|
||||||
double lat1 = latstart, lon1 = lonstart;
|
|
||||||
for(int time = 0; time <= 31536000.; time += AdvectionKernel::DT) {
|
|
||||||
// cout << setprecision(8) << lat1 << "," << setprecision(8) << lon1 << ",end" << i << "," << colour << endl;
|
|
||||||
try {
|
|
||||||
auto [templat, templon] = kernel.advect(time, lat1, lon1);
|
|
||||||
lat1 = templat;
|
|
||||||
lon1 = templon;
|
|
||||||
} catch (const out_of_range& e) {
|
|
||||||
cerr << "broke out of loop!" << endl;
|
|
||||||
time = 31536001;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << setprecision(8) << latstart << "," << setprecision(8) << lonstart << ",begin" << i << "," << colour << endl;
|
|
||||||
cout << setprecision(8) << lat1 << "," << setprecision(8) << lon1 << ",end" << i << "," << colour << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testGridIndexing(const UVGrid *uvGrid) {
|
|
||||||
int time = 20000;
|
|
||||||
cout << "=== land === (should all give 0)" << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 53.80956379699079, -1.6496306344654406) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 55.31428895563707, -2.851581041325997) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 47.71548983067583, -1.8704054037408626) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 56.23521060314398, 8.505979324950573) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 53.135645440244375, 8.505979324950573) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 56.44761278775708, -4.140629303756164) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 52.67625153110339, 0.8978569759455872) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 52.07154079279377, 4.627951041411331) << endl;
|
|
||||||
|
|
||||||
cout << "=== ocean === (should give not 0)" << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 47.43923166616274, -4.985451481829083) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 50.68943556852362, -9.306162999561733) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 53.70606799886677, -4.518347647034465) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 60.57987114267971, -12.208262973672621) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 46.532221548197285, -13.408189172582638) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 50.92725094937812, 1.3975824052375256) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 51.4028921682209, 2.4059571950925203) << endl;
|
|
||||||
cout << bilinearinterpolate(*uvGrid, time, 53.448445236769004, 0.7996966058017515) << endl;
|
|
||||||
// cout << bilinearinterpolate(*uvGrid, time, ) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
std::shared_ptr<UVGrid> uvGrid = std::make_shared<UVGrid>();
|
|
||||||
|
|
||||||
uvGrid->streamSlice(cout, 900);
|
|
||||||
|
|
||||||
auto kernelRK4 = RK4AdvectionKernel(uvGrid);
|
|
||||||
|
|
||||||
// You can use https://maps.co/gis/ to visualise these points
|
|
||||||
cout << "======= RK4 Integration =======" << endl;
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.53407391652826, 6.274975037862238, 0, "#ADD8E6");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.494053820479365, 5.673454142386921, 1, "#DC143C");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.49321966653616, 5.681867022043919, 2, "#50C878");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.581548701694324, 6.552600066543153, 3, "#FFEA00");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.431446729744124, 5.241592961691523, 4, "#663399");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.27913608324572, 4.82094897884165, 5, "#FFA500");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.18597595482688, 4.767667388308705, 6, "#008080");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 53.01592078792383, 4.6064205160882, 7, "#FFB6C1");
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 52.72816940158886, 4.5853883152993635, 8, "#36454F"); // on land
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 52.56142091881038, 4.502661662924255, 9, "#1E90FF"); // Dodger Blue
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 52.23202593893584, 4.2825246383181845, 10, "#FFD700"); // Gold
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 52.08062567609582, 4.112864890830927, 11, "#6A5ACD"); // Slate Blue
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.89497719759734, 3.8114033568921686, 12, "#20B2AA"); // Light Sea Green
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.752848503723634, 3.664177951809339, 13, "#FF69B4"); // Hot Pink
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.64595756528835, 3.626319993352851, 14, "#800080"); // Purple
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.55140730645238, 3.4326152213887986, 15, "#FF4500"); // Orange Red
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.45679776223422, 3.4452813365018384, 16, "#A52A2A"); // Brown
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.41444662720727, 3.4648562416765363, 17, "#4682B4"); // Steel Blue
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.37421261203866, 3.2449264214689455, 18, "#FF6347"); // Tomato
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.29651848898365, 2.9547572241424773, 19, "#008000"); // Green
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.19705098468974, 2.7647654914530024, 20, "#B8860B"); // Dark Goldenrod
|
|
||||||
advectForSomeTime(*uvGrid, kernelRK4, 51.114719857442665, 2.577076679365129, 21, "#FFC0CB"); // Pink
|
|
||||||
// advectForSomeTime(*uvGrid, kernelRK4, ,0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -9,68 +9,74 @@
|
||||||
|
|
||||||
#include "../CartographicTransformation.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);
|
||||||
renderer->DisplayToWorld();
|
renderer->DisplayToWorld();
|
||||||
renderer->GetWorldPoint(worldPos);
|
renderer->GetWorldPoint(worldPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *callData) {
|
void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *callData) {
|
||||||
// Note the use of reinterpret_cast to cast the caller to the expected type.
|
// Note the use of reinterpret_cast to cast the caller to the expected type.
|
||||||
auto interactor = reinterpret_cast<vtkRenderWindowInteractor *>(caller);
|
auto interactor = reinterpret_cast<vtkRenderWindowInteractor *>(caller);
|
||||||
|
|
||||||
if (evId == vtkCommand::LeftButtonPressEvent) {
|
if (evId == vtkCommand::LeftButtonPressEvent) {
|
||||||
dragging = true;
|
dragging = true;
|
||||||
}
|
}
|
||||||
if (evId == vtkCommand::LeftButtonReleaseEvent) {
|
if (evId == vtkCommand::LeftButtonReleaseEvent) {
|
||||||
dragging = false;
|
dragging = false;
|
||||||
}
|
}
|
||||||
if (!dragging) {
|
if (!dragging) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
interactor->GetEventPosition(x, y);
|
interactor->GetEventPosition(x, y);
|
||||||
|
|
||||||
double worldPos[4] = {2, 0 ,0, 0};
|
double worldPos[4] = {2, 0, 0, 0};
|
||||||
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};
|
||||||
ren->SetDisplayPoint(displayPos);
|
ren->SetDisplayPoint(displayPos);
|
||||||
ren->DisplayToWorld();
|
ren->DisplayToWorld();
|
||||||
ren->GetWorldPoint(worldPos);
|
ren->GetWorldPoint(worldPos);
|
||||||
inverseCartographicProjection->MultiplyPoint(worldPos, 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);
|
||||||
data->SetPoints(points);
|
data->SetPoints(points);
|
||||||
|
|
||||||
vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New();
|
vtkSmartPointer<vtkVertex> vertex = vtkSmartPointer<vtkVertex>::New();
|
||||||
vertex->GetPointIds()->SetId(0, id);
|
vertex->GetPointIds()->SetId(0, id);
|
||||||
|
|
||||||
vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();
|
vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();
|
||||||
vertices->InsertNextCell(vertex);
|
vertices->InsertNextCell(vertex);
|
||||||
data->SetVerts(vertices);
|
data->SetVerts(vertices);
|
||||||
ren->GetRenderWindow()->Render();
|
ren->GetRenderWindow()->Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SpawnPointCallback::SpawnPointCallback() : data(nullptr), points(nullptr), inverseCartographicProjection(nullptr) {
|
SpawnPointCallback::SpawnPointCallback() : data(nullptr),
|
||||||
inverseCartographicProjection = getCartographicTransformMatrix();
|
points(nullptr),
|
||||||
inverseCartographicProjection->Invert();
|
inverseCartographicProjection(nullptr),
|
||||||
}
|
uvGrid(nullptr) { }
|
||||||
|
|
||||||
SpawnPointCallback *SpawnPointCallback::New() {
|
SpawnPointCallback *SpawnPointCallback::New() {
|
||||||
return new SpawnPointCallback;
|
return new SpawnPointCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpawnPointCallback::setData(const vtkSmartPointer<vtkPolyData> &data) {
|
void SpawnPointCallback::setData(const vtkSmartPointer<vtkPolyData> &data) {
|
||||||
this->data = data;
|
this->data = 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) {
|
void SpawnPointCallback::setRen(const vtkSmartPointer<vtkRenderer> &ren) {
|
||||||
this->ren = ren;
|
this->ren = ren;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpawnPointCallback::setUVGrid(const std::shared_ptr<UVGrid> &uvGrid) {
|
||||||
|
this->uvGrid = uvGrid;
|
||||||
|
inverseCartographicProjection = getCartographicTransformMatrix(uvGrid);
|
||||||
|
inverseCartographicProjection->Invert();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,33 @@
|
||||||
#include <vtkPoints.h>
|
#include <vtkPoints.h>
|
||||||
#include <vtkPolyData.h>
|
#include <vtkPolyData.h>
|
||||||
#include <vtkMatrix4x4.h>
|
#include <vtkMatrix4x4.h>
|
||||||
|
#include "../advection/UVGrid.h"
|
||||||
|
|
||||||
class SpawnPointCallback : public vtkCallbackCommand {
|
class SpawnPointCallback : public vtkCallbackCommand {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SpawnPointCallback *New();
|
static SpawnPointCallback *New();
|
||||||
SpawnPointCallback();
|
|
||||||
|
|
||||||
void setPoints(const vtkSmartPointer<vtkPoints> &points);
|
SpawnPointCallback();
|
||||||
|
|
||||||
void setData(const vtkSmartPointer<vtkPolyData> &data);
|
void setPoints(const vtkSmartPointer<vtkPoints> &points);
|
||||||
|
|
||||||
|
void setData(const vtkSmartPointer<vtkPolyData> &data);
|
||||||
|
|
||||||
|
void setRen(const vtkSmartPointer<vtkRenderer> &ren);
|
||||||
|
|
||||||
|
void setUVGrid(const std::shared_ptr<UVGrid> &uvGrid);
|
||||||
|
|
||||||
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;
|
||||||
vtkSmartPointer<vtkMatrix4x4> inverseCartographicProjection;
|
std::shared_ptr<UVGrid> uvGrid;
|
||||||
|
vtkSmartPointer<vtkMatrix4x4> inverseCartographicProjection;
|
||||||
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,7 @@ void TimerCallbackCommand::setProgram(Program *program) {
|
||||||
void TimerCallbackCommand::setPaused(const bool val) {
|
void TimerCallbackCommand::setPaused(const bool val) {
|
||||||
this->paused = val;
|
this->paused = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimerCallbackCommand::setDt(int dt) {
|
||||||
|
this->dt = dt;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ public:
|
||||||
void setProgram(Program *program);
|
void setProgram(Program *program);
|
||||||
void setPaused(const bool val);
|
void setPaused(const bool val);
|
||||||
|
|
||||||
|
void setDt(int dt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int time;
|
int time;
|
||||||
int dt;
|
int dt;
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,8 @@ void EGlyphLayer::readCoordinates() {
|
||||||
int lonIndex = 0;
|
int lonIndex = 0;
|
||||||
for (double lon: uvGrid->lons) {
|
for (double lon: uvGrid->lons) {
|
||||||
auto [u, v] = (*uvGrid)[0, latIndex, lonIndex];
|
auto [u, v] = (*uvGrid)[0, latIndex, lonIndex];
|
||||||
direction->SetTuple3(i, 2*v, 2*u, 0);
|
direction->SetTuple3(i, 5*u, 5*v, 0);
|
||||||
points->InsertPoint(i++, lon, lat, 0);
|
points->InsertPoint(i++, lon, lat, 0);
|
||||||
// see also https://vtk.org/doc/nightly/html/classvtkPolyDataMapper2D.html
|
|
||||||
lonIndex++;
|
lonIndex++;
|
||||||
}
|
}
|
||||||
latIndex++;
|
latIndex++;
|
||||||
|
|
@ -61,7 +60,7 @@ 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();
|
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter(uvGrid);
|
||||||
transformFilter->SetInputData(data);
|
transformFilter->SetInputData(data);
|
||||||
|
|
||||||
vtkNew<vtkGlyphSource2D> arrowSource;
|
vtkNew<vtkGlyphSource2D> arrowSource;
|
||||||
|
|
@ -101,7 +100,8 @@ void EGlyphLayer::updateData(int t) {
|
||||||
for (int lat = 0; lat < uvGrid->latSize; lat++) {
|
for (int lat = 0; lat < uvGrid->latSize; lat++) {
|
||||||
for (int lon = 0; lon < uvGrid->lonSize; lon++) {
|
for (int lon = 0; lon < uvGrid->lonSize; lon++) {
|
||||||
auto [u, v] = (*uvGrid)[t/3600, lat, lon];
|
auto [u, v] = (*uvGrid)[t/3600, lat, lon];
|
||||||
this->direction->SetTuple3(i, 5*v, 5*u, 0); // FIXME: fetch data from file.
|
// TODO: The 5*v stuff should really be a filter transform
|
||||||
|
this->direction->SetTuple3(i, 5*u, 5*v, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
|
||||||
newPointCallBack->setData(data);
|
newPointCallBack->setData(data);
|
||||||
newPointCallBack->setPoints(points);
|
newPointCallBack->setPoints(points);
|
||||||
newPointCallBack->setRen(ren);
|
newPointCallBack->setRen(ren);
|
||||||
|
newPointCallBack->setUVGrid(uvGrid);
|
||||||
return newPointCallBack;
|
return newPointCallBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ 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.
|
// 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(std::unique_ptr<AdvectionKernel> advectionKernel) {
|
LGlyphLayer::LGlyphLayer(std::shared_ptr<UVGrid> uvGrid, std::unique_ptr<AdvectionKernel> advectionKernel) {
|
||||||
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
||||||
this->ren->SetLayer(2);
|
this->ren->SetLayer(2);
|
||||||
|
|
||||||
|
|
@ -40,13 +41,12 @@ LGlyphLayer::LGlyphLayer(std::unique_ptr<AdvectionKernel> advectionKernel) {
|
||||||
this->data->SetPoints(this->points);
|
this->data->SetPoints(this->points);
|
||||||
|
|
||||||
advector = std::move(advectionKernel);
|
advector = std::move(advectionKernel);
|
||||||
|
this->uvGrid = uvGrid;
|
||||||
|
|
||||||
auto camera = createNormalisedCamera();
|
auto camera = createNormalisedCamera();
|
||||||
ren->SetActiveCamera(camera);
|
ren->SetActiveCamera(camera);
|
||||||
|
|
||||||
auto transform = createCartographicTransformFilter();
|
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter(uvGrid);
|
||||||
|
|
||||||
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
|
||||||
transformFilter->SetInputData(data);
|
transformFilter->SetInputData(data);
|
||||||
|
|
||||||
vtkNew<vtkGlyphSource2D> circleSource;
|
vtkNew<vtkGlyphSource2D> circleSource;
|
||||||
|
|
@ -97,10 +97,7 @@ void LGlyphLayer::updateData(int t) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
||||||
auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::New();
|
auto newPointCallBack = createSpawnPointCallback();
|
||||||
newPointCallBack->setData(data);
|
|
||||||
newPointCallBack->setPoints(points);
|
|
||||||
newPointCallBack->setRen(ren);
|
|
||||||
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, newPointCallBack);
|
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, newPointCallBack);
|
||||||
interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, newPointCallBack);
|
interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, newPointCallBack);
|
||||||
interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack);
|
interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack);
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,12 @@ private:
|
||||||
vtkSmartPointer<vtkPoints> points;
|
vtkSmartPointer<vtkPoints> points;
|
||||||
vtkSmartPointer<vtkPolyData> data;
|
vtkSmartPointer<vtkPolyData> data;
|
||||||
std::unique_ptr<AdvectionKernel> advector;
|
std::unique_ptr<AdvectionKernel> advector;
|
||||||
|
std::shared_ptr<UVGrid> uvGrid;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
*/
|
*/
|
||||||
LGlyphLayer(std::unique_ptr<AdvectionKernel> advectionKernel);
|
LGlyphLayer(std::shared_ptr<UVGrid> uvGrid, std::unique_ptr<AdvectionKernel> advectionKernel);
|
||||||
|
|
||||||
/** This function spoofs a few points in the dataset. Mostly used for testing.
|
/** This function spoofs a few points in the dataset. Mostly used for testing.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,16 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define DT 60 * 60 // 60 sec/min * 60 mins
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
shared_ptr<UVGrid> uvGrid = std::make_shared<UVGrid>();
|
shared_ptr<UVGrid> uvGrid = std::make_shared<UVGrid>();
|
||||||
auto kernelRK4 = make_unique<RK4AdvectionKernel>(uvGrid);
|
auto kernelRK4 = make_unique<RK4AdvectionKernel>(uvGrid, DT);
|
||||||
|
|
||||||
auto l = new LGlyphLayer(move(kernelRK4));
|
auto l = new LGlyphLayer(uvGrid, move(kernelRK4));
|
||||||
// l->spoofPoints();
|
// l->spoofPoints();
|
||||||
|
|
||||||
Program *program = new Program();
|
Program *program = new Program(DT);
|
||||||
program->addLayer(new BackgroundImage("../../../../data/map_661-661.png"));
|
program->addLayer(new BackgroundImage("../../../../data/map_661-661.png"));
|
||||||
program->addLayer(new EGlyphLayer(uvGrid));
|
program->addLayer(new EGlyphLayer(uvGrid));
|
||||||
program->addLayer(l);
|
program->addLayer(l);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue