diff --git a/vtk/src/CMakeLists.txt b/vtk/src/CMakeLists.txt index ef2a3aa..1ba0d72 100644 --- a/vtk/src/CMakeLists.txt +++ b/vtk/src/CMakeLists.txt @@ -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( diff --git a/vtk/src/Program.cpp b/vtk/src/Program.cpp index f5d1a93..d35aa6a 100644 --- a/vtk/src/Program.cpp +++ b/vtk/src/Program.cpp @@ -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::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::New(); this->interact = vtkSmartPointer::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) { diff --git a/vtk/src/Program.h b/vtk/src/Program.h index 4097e4c..e92b5aa 100644 --- a/vtk/src/Program.h +++ b/vtk/src/Program.h @@ -6,7 +6,6 @@ #include #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 interact; + + /** The camera used by all layers for this program. + */ + vtkSmartPointer 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. */ diff --git a/vtk/src/commands/CameraMoveCallback.cpp b/vtk/src/commands/CameraMoveCallback.cpp new file mode 100644 index 0000000..6a92f0b --- /dev/null +++ b/vtk/src/commands/CameraMoveCallback.cpp @@ -0,0 +1,74 @@ +#include "CameraMoveCallback.h" + +#include +#include +#include +#include +#include +#include + +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(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 &cam) { + this->cam = cam; +} diff --git a/vtk/src/commands/CameraMoveCallback.h b/vtk/src/commands/CameraMoveCallback.h new file mode 100644 index 0000000..e63adcf --- /dev/null +++ b/vtk/src/commands/CameraMoveCallback.h @@ -0,0 +1,27 @@ +#ifndef VTKBASE_CAMERAMOVECALLBACK_H +#define VTKBASE_CAMERAMOVECALLBACK_H + + +#include +#include +#include +#include + +class CameraMoveCallback : public vtkCallbackCommand { + +public: + static CameraMoveCallback *New(vtkCamera *cam); + CameraMoveCallback(); + + void setCam(const vtkSmartPointer &cam); + +private: + vtkSmartPointer cam; + + void Execute(vtkObject *caller, unsigned long evId, void *callData) override; + void zoom(const bool in); + void pan(const std::string dir); +}; + + +#endif diff --git a/vtk/src/commands/SpawnPointCallback.cpp b/vtk/src/commands/SpawnPointCallback.cpp index e29d190..3f41acd 100644 --- a/vtk/src/commands/SpawnPointCallback.cpp +++ b/vtk/src/commands/SpawnPointCallback.cpp @@ -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); diff --git a/vtk/src/commands/TimerCallbackCommand.cpp b/vtk/src/commands/TimerCallbackCommand.cpp index 94e9de9..6700ac5 100644 --- a/vtk/src/commands/TimerCallbackCommand.cpp +++ b/vtk/src/commands/TimerCallbackCommand.cpp @@ -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; } diff --git a/vtk/src/layers/BackgroundImage.cpp b/vtk/src/layers/BackgroundImage.cpp index 780eaae..925c27a 100644 --- a/vtk/src/layers/BackgroundImage.cpp +++ b/vtk/src/layers/BackgroundImage.cpp @@ -3,6 +3,7 @@ #include #include #include +#include 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 transformFilter = createCartographicTransformFilter(); + // transformFilter->SetInputData(imageData); + vtkNew 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. +} diff --git a/vtk/src/layers/BackgroundImage.h b/vtk/src/layers/BackgroundImage.h index 1061189..c837b87 100644 --- a/vtk/src/layers/BackgroundImage.h +++ b/vtk/src/layers/BackgroundImage.h @@ -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 diff --git a/vtk/src/layers/EGlyphLayer.cpp b/vtk/src/layers/EGlyphLayer.cpp index cb91825..b4d5b28 100644 --- a/vtk/src/layers/EGlyphLayer.cpp +++ b/vtk/src/layers/EGlyphLayer.cpp @@ -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 diff --git a/vtk/src/layers/LGlyphLayer.cpp b/vtk/src/layers/LGlyphLayer.cpp index 845d628..a49ee7f 100644 --- a/vtk/src/layers/LGlyphLayer.cpp +++ b/vtk/src/layers/LGlyphLayer.cpp @@ -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 transformFilter = createCartographicTransformFilter(); transformFilter->SetInputData(data); diff --git a/vtk/src/layers/Layer.cpp b/vtk/src/layers/Layer.cpp index 39073b1..e7a156d 100644 --- a/vtk/src/layers/Layer.cpp +++ b/vtk/src/layers/Layer.cpp @@ -15,3 +15,8 @@ void Layer::updateData(int t) { void Layer::addObservers(vtkSmartPointer interactor) { // By default, do nothing } + + +void Layer::setCamera(vtkCamera *camera) { + this->getLayer()->SetActiveCamera(camera); +} diff --git a/vtk/src/layers/Layer.h b/vtk/src/layers/Layer.h index 5f6fc32..fd20823 100644 --- a/vtk/src/layers/Layer.h +++ b/vtk/src/layers/Layer.h @@ -27,6 +27,11 @@ public: * @param interactor : pointer to the interactor that observers can be added to. */ virtual void addObservers(vtkSmartPointer 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 diff --git a/vtk/src/main.cpp b/vtk/src/main.cpp index fb89ea4..bfe345e 100644 --- a/vtk/src/main.cpp +++ b/vtk/src/main.cpp @@ -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());