feat (wip): implementing camera zooming and panning functionality
This commit is contained in:
parent
cd87f383c9
commit
4d743a42c1
|
|
@ -14,6 +14,8 @@ find_package(VTK COMPONENTS
|
|||
FiltersProgrammable
|
||||
FiltersSources
|
||||
ImagingSources
|
||||
ImagingGeneral
|
||||
ImagingCore
|
||||
InteractionStyle
|
||||
IOImage
|
||||
RenderingContextOpenGL2
|
||||
|
|
@ -32,21 +34,23 @@ endif()
|
|||
find_package(netCDF REQUIRED)
|
||||
|
||||
add_executable(VtkBase MACOSX_BUNDLE main.cpp
|
||||
layers/BackgroundImage.cpp
|
||||
layers/BackgroundImage.h
|
||||
layers/EGlyphLayer.cpp
|
||||
layers/EGlyphLayer.h
|
||||
layers/Layer.cpp
|
||||
layers/Layer.h
|
||||
layers/LGlyphLayer.cpp
|
||||
layers/LGlyphLayer.h
|
||||
Program.cpp
|
||||
Program.h
|
||||
commands/TimerCallbackCommand.h
|
||||
CartographicTransformation.cpp
|
||||
commands/CameraMoveCallback.cpp
|
||||
commands/CameraMoveCallback.h
|
||||
commands/SpawnPointCallback.cpp
|
||||
commands/SpawnPointCallback.h
|
||||
commands/TimerCallbackCommand.cpp
|
||||
commands/SpawnPointCallback.h
|
||||
commands/SpawnPointCallback.cpp
|
||||
CartographicTransformation.cpp
|
||||
commands/TimerCallbackCommand.h
|
||||
layers/BackgroundImage.cpp
|
||||
layers/BackgroundImage.h
|
||||
layers/EGlyphLayer.cpp
|
||||
layers/EGlyphLayer.h
|
||||
layers/Layer.cpp
|
||||
layers/Layer.h
|
||||
layers/LGlyphLayer.cpp
|
||||
layers/LGlyphLayer.h
|
||||
Program.cpp
|
||||
Program.h
|
||||
)
|
||||
|
||||
execute_process(
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
#include "Program.h"
|
||||
#include "commands/TimerCallbackCommand.h"
|
||||
#include "commands/SpawnPointCallback.h"
|
||||
#include "CartographicTransformation.h"
|
||||
#include "commands/CameraMoveCallback.h"
|
||||
|
||||
void Program::setWinProperties() {
|
||||
this->win->SetWindowName("Simulation");
|
||||
|
|
@ -40,17 +41,28 @@ void Program::setupTimer() {
|
|||
this->interact->CreateRepeatingTimer(17); // 60 fps == 1000 / 60 == 16.7 ms per frame
|
||||
}
|
||||
|
||||
void Program::setupCameraCallback() {
|
||||
auto callback = vtkSmartPointer<CameraMoveCallback>::New(this->cam);
|
||||
this->interact->AddObserver(vtkCommand::MouseWheelForwardEvent, callback);
|
||||
this->interact->AddObserver(vtkCommand::MouseWheelBackwardEvent, callback);
|
||||
this->interact->AddObserver(vtkCommand::KeyPressEvent, callback);
|
||||
}
|
||||
|
||||
Program::Program() {
|
||||
this->win = vtkSmartPointer<vtkRenderWindow>::New();
|
||||
this->interact = vtkSmartPointer<vtkRenderWindowInteractor>::New();
|
||||
this->cam = createNormalisedCamera();
|
||||
|
||||
this->win->SetNumberOfLayers(0);
|
||||
setWinProperties();
|
||||
setupTimer();
|
||||
setupCameraCallback();
|
||||
}
|
||||
|
||||
|
||||
void Program::addLayer(Layer *layer) {
|
||||
layer->setCamera(this->cam);
|
||||
|
||||
this->layers.push_back(layer);
|
||||
this->win->AddRenderer(layer->getLayer());
|
||||
this->win->SetNumberOfLayers(this->win->GetNumberOfLayers() + 1);
|
||||
|
|
@ -66,6 +78,7 @@ void Program::removeLayer(Layer *layer) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Program::updateData(int t) {
|
||||
win->Render();
|
||||
for (Layer *l: layers) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include <vtkRenderer.h>
|
||||
|
||||
#include "layers/Layer.h"
|
||||
#include "commands/SpawnPointCallback.h"
|
||||
|
||||
/** This class manages the upper levels of the vtk pipeline; it has attributes for the vtkrenderWindow and a vector of Layers to represent a variable number of vtkRenderers.
|
||||
* It can also set up a vtkTimer by connecting an instance of TimerCallbackCommand with its contained vtkRenderWindowInteractor.
|
||||
|
|
@ -25,6 +24,11 @@ private:
|
|||
*/
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> interact;
|
||||
|
||||
|
||||
/** The camera used by all layers for this program.
|
||||
*/
|
||||
vtkSmartPointer<vtkCamera> cam;
|
||||
|
||||
/** This function sets some default properties on the vtkRenderWindow. Extracted to its' own function to keep the constructor from becoming cluttered.
|
||||
*/
|
||||
void setWinProperties();
|
||||
|
|
@ -33,8 +37,14 @@ private:
|
|||
*/
|
||||
void setupTimer();
|
||||
|
||||
/** This function adds all interactors of each layer to the interactor/window
|
||||
*/
|
||||
void setupInteractions();
|
||||
|
||||
/** This function sets up the camera's associated movement callbacks..
|
||||
*/
|
||||
void setupCameraCallback();
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
#include "CameraMoveCallback.h"
|
||||
|
||||
#include <vtkVertex.h>
|
||||
#include <vtkRenderer.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkCommand.h>
|
||||
#include <vtkRenderWindow.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
void CameraMoveCallback::Execute(vtkObject *caller, unsigned long evId,
|
||||
void *callData) {
|
||||
// Note the use of reinterpret_cast to cast the caller to the expected type.
|
||||
auto interactor = reinterpret_cast<vtkRenderWindowInteractor *>(caller);
|
||||
|
||||
switch (evId) {
|
||||
case vtkCommand::KeyPressEvent:
|
||||
pan(interactor->GetKeySym());
|
||||
break;
|
||||
case vtkCommand::MouseWheelForwardEvent:
|
||||
zoom(true);
|
||||
break;
|
||||
case vtkCommand::MouseWheelBackwardEvent:
|
||||
zoom(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CameraMoveCallback::zoom(const bool in) {
|
||||
double pos[3];
|
||||
this->cam->GetPosition(pos);
|
||||
|
||||
if (in) {
|
||||
pos[2] -= 50;
|
||||
} else {
|
||||
pos[2] += 50;
|
||||
}
|
||||
this->cam->SetPosition(pos);
|
||||
|
||||
}
|
||||
|
||||
void CameraMoveCallback::pan(const string dir) {
|
||||
double pos[3];
|
||||
this->cam->GetPosition(pos);
|
||||
|
||||
if (dir == "Left" or dir == "h") {
|
||||
pos[0] -= 1;
|
||||
this->cam->SetPosition(pos);
|
||||
} else if (dir == "Up" or dir == "j" ) {
|
||||
pos[1] += 1;
|
||||
this->cam->SetPosition(pos);
|
||||
} else if (dir == "Right" or dir == "k" ) {
|
||||
pos[0] += 1;
|
||||
this->cam->SetPosition(pos);
|
||||
} else if (dir == "Down" or dir == "l" ) {
|
||||
pos[1] -= 1;
|
||||
this->cam->SetPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
CameraMoveCallback::CameraMoveCallback() : cam(nullptr) {}
|
||||
|
||||
CameraMoveCallback *CameraMoveCallback::New(vtkCamera *cam) {
|
||||
auto me = new CameraMoveCallback;
|
||||
me->setCam(cam);
|
||||
return me;
|
||||
}
|
||||
|
||||
void CameraMoveCallback::setCam(const vtkSmartPointer<vtkCamera> &cam) {
|
||||
this->cam = cam;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef VTKBASE_CAMERAMOVECALLBACK_H
|
||||
#define VTKBASE_CAMERAMOVECALLBACK_H
|
||||
|
||||
|
||||
#include <vtkCallbackCommand.h>
|
||||
#include <vtkCamera.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkMatrix4x4.h>
|
||||
|
||||
class CameraMoveCallback : public vtkCallbackCommand {
|
||||
|
||||
public:
|
||||
static CameraMoveCallback *New(vtkCamera *cam);
|
||||
CameraMoveCallback();
|
||||
|
||||
void setCam(const vtkSmartPointer<vtkCamera> &cam);
|
||||
|
||||
private:
|
||||
vtkSmartPointer<vtkCamera> cam;
|
||||
|
||||
void Execute(vtkObject *caller, unsigned long evId, void *callData) override;
|
||||
void zoom(const bool in);
|
||||
void pan(const std::string dir);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -39,7 +39,7 @@ void SpawnPointCallback::Execute(vtkObject *caller, unsigned long evId, void *ca
|
|||
ren->DisplayToWorld();
|
||||
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);
|
||||
data->SetPoints(points);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "../Program.h"
|
||||
|
||||
|
||||
// TODO: add getter/setters to attributes for customizability.
|
||||
TimerCallbackCommand::TimerCallbackCommand() : dt(3600), maxTime(3600*24*365), time(0) {}
|
||||
|
||||
TimerCallbackCommand* TimerCallbackCommand::New(Program *program) {
|
||||
|
|
@ -22,7 +23,6 @@ void TimerCallbackCommand::Execute(vtkObject* caller, unsigned long eventId, voi
|
|||
}
|
||||
|
||||
|
||||
|
||||
void TimerCallbackCommand::setProgram(Program *program) {
|
||||
this->program = program;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <vtkImageActor.h>
|
||||
#include <vtkImageData.h>
|
||||
#include <vtkImageReader2.h>
|
||||
#include <vtkTransformFilter.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
|
@ -24,6 +25,13 @@ void BackgroundImage::updateImage() {
|
|||
imageReader->Update();
|
||||
imageData = imageReader->GetOutput();
|
||||
|
||||
// TODO: transform the iamge to the range [-1,1] and center it on (0,0)/
|
||||
// This will allow the backgorundImage to share a camera with our other layers.
|
||||
// Facilitating the cameraMovement callback.
|
||||
|
||||
// vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
||||
// transformFilter->SetInputData(imageData);
|
||||
|
||||
vtkNew<vtkImageActor> imageActor;
|
||||
imageActor->SetInputData(imageData);
|
||||
|
||||
|
|
@ -60,3 +68,8 @@ void BackgroundImage::setImagePath(string imagePath) {
|
|||
this->imagePath = imagePath;
|
||||
updateImage();
|
||||
}
|
||||
|
||||
|
||||
void BackgroundImage::setCamera(vtkCamera *cam) {
|
||||
// TODO: fix the camera for this layer so this intentionally empty override can be removed.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ public:
|
|||
* @param imagePath : String to the path of the new image to use.
|
||||
*/
|
||||
void setImagePath(std::string imagePath);
|
||||
|
||||
|
||||
void setCamera(vtkCamera *cam) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,13 +65,13 @@ void EGlyphLayer::readCoordinates() {
|
|||
this->direction->SetNumberOfTuples(numLats*numLons);
|
||||
points->Allocate(numLats*numLons);
|
||||
|
||||
auto camera = createNormalisedCamera();
|
||||
ren->SetActiveCamera(camera);
|
||||
// auto camera = createNormalisedCamera();
|
||||
// ren->SetActiveCamera(camera);
|
||||
|
||||
int i = 0;
|
||||
for (double lat : lats) {
|
||||
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
|
||||
points->InsertPoint(i++, lon, lat, 0);
|
||||
// see also https://vtk.org/doc/nightly/html/classvtkPolyDataMapper2D.html
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ LGlyphLayer::LGlyphLayer() {
|
|||
auto camera = createNormalisedCamera();
|
||||
ren->SetActiveCamera(camera);
|
||||
|
||||
auto transform = createCartographicTransformFilter();
|
||||
// TODO: this line seemed to do nothing?
|
||||
// auto transform = createCartographicTransformFilter();
|
||||
|
||||
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
||||
transformFilter->SetInputData(data);
|
||||
|
|
|
|||
|
|
@ -15,3 +15,8 @@ void Layer::updateData(int t) {
|
|||
void Layer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
||||
// By default, do nothing
|
||||
}
|
||||
|
||||
|
||||
void Layer::setCamera(vtkCamera *camera) {
|
||||
this->getLayer()->SetActiveCamera(camera);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ public:
|
|||
* @param interactor : pointer to the interactor that observers can be added to.
|
||||
*/
|
||||
virtual void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor);
|
||||
|
||||
/** Sets the active camera for the vtkRenderer associated with this layer.
|
||||
* Used to share one camera between multiple layers.
|
||||
*/
|
||||
virtual void setCamera(vtkCamera *camera);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "layers/EGlyphLayer.h"
|
||||
#include "layers/LGlyphLayer.h"
|
||||
#include "Program.h"
|
||||
#include "CartographicTransformation.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -20,6 +22,7 @@ int main() {
|
|||
auto l = new LGlyphLayer();
|
||||
l->spoofPoints();
|
||||
|
||||
|
||||
Program *program = new Program();
|
||||
program->addLayer(new BackgroundImage("../../../../data/map_661-661.png"));
|
||||
program->addLayer(new EGlyphLayer());
|
||||
|
|
|
|||
Loading…
Reference in New Issue