fix: stylistic changes + addObservers
This commit is contained in:
62
vtk/src/layers/BackgroundImage.cpp
Normal file
62
vtk/src/layers/BackgroundImage.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "BackgroundImage.h"
|
||||
#include <vtkCamera.h>
|
||||
#include <vtkImageActor.h>
|
||||
#include <vtkImageData.h>
|
||||
#include <vtkImageReader2.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
BackgroundImage::BackgroundImage(string imagePath) : imagePath(imagePath) {
|
||||
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
||||
this->ren->SetLayer(0);
|
||||
this->ren->InteractiveOff();
|
||||
updateImage();
|
||||
}
|
||||
|
||||
|
||||
void BackgroundImage::updateImage() {
|
||||
vtkSmartPointer<vtkImageData> imageData;
|
||||
|
||||
vtkSmartPointer<vtkImageReader2> imageReader;
|
||||
|
||||
imageReader.TakeReference(this->readerFactory->CreateImageReader2(this->imagePath.c_str()));
|
||||
imageReader->SetFileName(this->imagePath.c_str());
|
||||
imageReader->Update();
|
||||
imageData = imageReader->GetOutput();
|
||||
|
||||
vtkNew<vtkImageActor> imageActor;
|
||||
imageActor->SetInputData(imageData);
|
||||
|
||||
this->ren->AddActor(imageActor);
|
||||
|
||||
|
||||
// camera stuff
|
||||
// essentially sets the camera to the middle of the background, and points it at the background
|
||||
// TODO: extract this to its own function, separate from the background class.
|
||||
double origin[3], spacing[3];
|
||||
int extent[6];
|
||||
imageData->GetOrigin(origin);
|
||||
imageData->GetSpacing(spacing);
|
||||
imageData->GetExtent(extent);
|
||||
|
||||
vtkCamera *camera = this->ren->GetActiveCamera();
|
||||
camera->ParallelProjectionOn();
|
||||
|
||||
double xc = origin[0] + 0.5 * (extent[0] + extent[1]) * spacing[0];
|
||||
double yc = origin[1] + 0.5 * (extent[2] + extent[3]) * spacing[1];
|
||||
double yd = (extent[3] - extent[2] + 1) * spacing[1];
|
||||
double d = camera->GetDistance();
|
||||
camera->SetParallelScale(0.5 * yd);
|
||||
camera->SetFocalPoint(xc, yc, 0.0);
|
||||
camera->SetPosition(xc, yc, d);
|
||||
}
|
||||
|
||||
|
||||
string BackgroundImage::getImagePath() {
|
||||
return this->imagePath;
|
||||
}
|
||||
|
||||
void BackgroundImage::setImagePath(string imagePath) {
|
||||
this->imagePath = imagePath;
|
||||
updateImage();
|
||||
}
|
||||
37
vtk/src/layers/BackgroundImage.h
Normal file
37
vtk/src/layers/BackgroundImage.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef BACKGROUND_H
|
||||
#define BACKGROUND_H
|
||||
|
||||
#include "Layer.h"
|
||||
#include <vtkImageReader2Factory.h>
|
||||
|
||||
/** Implements the Layer class for the case of a background image.
|
||||
* Specifically, reads a backgroundImage given by the imagePath attribute and puts it on layer 0.
|
||||
*/
|
||||
class BackgroundImage : public Layer {
|
||||
private:
|
||||
std::string imagePath;
|
||||
vtkSmartPointer<vtkImageReader2Factory> readerFactory;
|
||||
|
||||
/** This private function updates the background image using the imagePath attribute.
|
||||
*/
|
||||
void updateImage();
|
||||
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
* @param imagePath : String to the path of the image to use as background.
|
||||
*/
|
||||
BackgroundImage(std::string imagePath);
|
||||
|
||||
/** Getter.
|
||||
* @return the imagePath attribute.
|
||||
*/
|
||||
std::string getImagePath();
|
||||
|
||||
/** Setter. Can be used to change the background image
|
||||
* @param imagePath : String to the path of the new image to use.
|
||||
*/
|
||||
void setImagePath(std::string imagePath);
|
||||
};
|
||||
|
||||
#endif
|
||||
124
vtk/src/layers/EGlyphLayer.cpp
Normal file
124
vtk/src/layers/EGlyphLayer.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "EGlyphLayer.h"
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkGlyphSource2D.h>
|
||||
#include <vtkRegularPolygonSource.h>
|
||||
#include <vtkGlyph2D.h>
|
||||
#include <vtkActor2D.h>
|
||||
#include <vtkNamedColors.h>
|
||||
#include <vtkPolyDataMapper2D.h>
|
||||
#include <vtkPolyDataMapper.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkProperty2D.h>
|
||||
#include <vtkVertexGlyphFilter.h>
|
||||
#include <netcdf>
|
||||
#include <vtkArrowSource.h>
|
||||
#include "../CartographicTransformation.h"
|
||||
|
||||
using namespace netCDF;
|
||||
using namespace std;
|
||||
|
||||
template <typename T>
|
||||
vector<T> getVarVector(const NcVar &var) {
|
||||
int length = 1;
|
||||
for (NcDim dim : var.getDims()) {
|
||||
length *= dim.getSize();
|
||||
}
|
||||
|
||||
vector<T> vec(length);
|
||||
|
||||
var.getVar(vec.data());
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
tuple<vector<int>, vector<double>, vector<double>> readGrid() {
|
||||
netCDF::NcFile data("../../../../data/grid.h5", netCDF::NcFile::read);
|
||||
multimap< string, NcVar > vars = data.getVars();
|
||||
vector<int> time = getVarVector<int>(vars.find("times")->second);
|
||||
vector<double> longitude = getVarVector<double>(vars.find("longitude")->second);
|
||||
vector<double> latitude = getVarVector<double>(vars.find("latitude")->second);
|
||||
|
||||
return {time, latitude, longitude};
|
||||
}
|
||||
|
||||
|
||||
EGlyphLayer::EGlyphLayer() {
|
||||
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
||||
this->ren->SetLayer(1);
|
||||
this->ren->InteractiveOff();
|
||||
|
||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||
this->direction = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
this->direction->SetName("direction");
|
||||
readCoordinates();
|
||||
}
|
||||
|
||||
|
||||
void EGlyphLayer::readCoordinates() {
|
||||
vtkNew<vtkPoints> points;
|
||||
auto [times, lats, lons] = readGrid(); // FIXME: import Robin's readData function and use it
|
||||
this->numLats = lats.size();
|
||||
this->numLons = lons.size();
|
||||
|
||||
this->direction->SetNumberOfComponents(3);
|
||||
this->direction->SetNumberOfTuples(numLats*numLons);
|
||||
points->Allocate(numLats*numLons);
|
||||
|
||||
auto camera = createNormalisedCamera();
|
||||
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++, lon, lat, 0);
|
||||
// see also https://vtk.org/doc/nightly/html/classvtkPolyDataMapper2D.html
|
||||
}
|
||||
}
|
||||
this->data->SetPoints(points);
|
||||
this->data->GetPointData()->AddArray(this->direction);
|
||||
this->data->GetPointData()->SetActiveVectors("direction");
|
||||
|
||||
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
||||
transformFilter->SetInputData(data);
|
||||
|
||||
vtkNew<vtkGlyphSource2D> arrowSource;
|
||||
arrowSource->SetGlyphTypeToArrow();
|
||||
arrowSource->SetScale(0.2); //TODO: set this properly
|
||||
arrowSource->Update();
|
||||
|
||||
vtkNew<vtkGlyph2D> glyph2D;
|
||||
glyph2D->SetSourceConnection(arrowSource->GetOutputPort());
|
||||
glyph2D->SetInputConnection(transformFilter->GetOutputPort());
|
||||
glyph2D->OrientOn();
|
||||
glyph2D->ClampingOn();
|
||||
glyph2D->SetScaleModeToScaleByVector();
|
||||
glyph2D->SetVectorModeToUseVector();
|
||||
glyph2D->Update();
|
||||
|
||||
// vtkNew<vtkCoordinate> coordinate;
|
||||
// coordinate->SetCoordinateSystemToWorld();
|
||||
|
||||
vtkNew<vtkPolyDataMapper>(mapper);
|
||||
// mapper->SetTransformCoordinate(coordinate);
|
||||
mapper->SetInputConnection(glyph2D->GetOutputPort());
|
||||
mapper->Update();
|
||||
|
||||
vtkNew<vtkActor> actor;
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
actor->GetProperty()->SetColor(0,0,0);
|
||||
actor->GetProperty()->SetOpacity(0.2);
|
||||
|
||||
this->ren->AddActor(actor) ;
|
||||
}
|
||||
|
||||
|
||||
void EGlyphLayer::updateData(int t) {
|
||||
for (int i=0; i < numLats*numLons; i++) {
|
||||
this->direction->SetTuple3(i, std::cos(t), std::sin(t), 0); // FIXME: fetch data from file.
|
||||
}
|
||||
this->direction->Modified();
|
||||
}
|
||||
35
vtk/src/layers/EGlyphLayer.h
Normal file
35
vtk/src/layers/EGlyphLayer.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef EGLYPHLAYER_H
|
||||
#define EGLYPHLAYER_H
|
||||
|
||||
#include "Layer.h"
|
||||
#include <vtkPolyData.h>
|
||||
|
||||
/** Implements the Layer class for the case of a Eulerian visualization.
|
||||
* Specifically, this class models the eulerian flow-fields of the simulation using the 'glyph' mark and 'direction' and 'form' channels to denote direction and strength of velocities.
|
||||
*/
|
||||
class EGlyphLayer : public Layer {
|
||||
private:
|
||||
vtkSmartPointer<vtkPolyData> data;
|
||||
vtkSmartPointer<vtkDoubleArray> direction;
|
||||
int numLats;
|
||||
int numLons;
|
||||
|
||||
/** This private function sets up the initial coordinates for the glyphs in the dataset.
|
||||
* It also reads some initial data to actually display.
|
||||
*/
|
||||
void readCoordinates();
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
*/
|
||||
EGlyphLayer();
|
||||
|
||||
/** updates the glyphs to reflect the given timestamp in the dataset.
|
||||
* @param t : the time at which to fetch the data.
|
||||
*/
|
||||
void updateData(int t);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
105
vtk/src/layers/LGlyphLayer.cpp
Normal file
105
vtk/src/layers/LGlyphLayer.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "LGlyphLayer.h"
|
||||
#include "../commands/SpawnPointCallback.h"
|
||||
#include <vtkActor2D.h>
|
||||
#include <vtkGlyph2D.h>
|
||||
#include <vtkGlyphSource2D.h>
|
||||
#include <vtkNamedColors.h>
|
||||
#include <vtkPolyDataMapper2D.h>
|
||||
#include <vtkProperty2D.h>
|
||||
#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 "../CartographicTransformation.h"
|
||||
|
||||
|
||||
vtkSmartPointer<SpawnPointCallback> LGlyphLayer::createSpawnPointCallback() {
|
||||
auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::New();
|
||||
newPointCallBack->setData(data);
|
||||
newPointCallBack->setPoints(points);
|
||||
newPointCallBack->setRen(ren);
|
||||
return newPointCallBack;
|
||||
}
|
||||
|
||||
// Further notes; current thinking is to allow tracking a particle's age by using a scalar array in the VtkPolyData. This would be incremented for every tick/updateData function call.
|
||||
// Another challenge is the concept of beaching; dead particles must not be included in the advect function call (wasted computations), but they should not be outright deleted from the vtkPoints either (we still want to display them). Working Solution: have another array of ints in the vtkPolyData, which tracks for how many calls of UpdateData a given particle has not had its position changed. If this int reaches some treshold (5? 10? 3? needs some testing), exclude the particle from the advect call.
|
||||
//
|
||||
// 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->points = vtkSmartPointer<vtkPoints>::New();
|
||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||
this->data->SetPoints(this->points);
|
||||
|
||||
auto camera = createNormalisedCamera();
|
||||
ren->SetActiveCamera(camera);
|
||||
|
||||
auto transform = createCartographicTransformFilter();
|
||||
|
||||
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter();
|
||||
transformFilter->SetInputData(data);
|
||||
|
||||
vtkNew<vtkGlyphSource2D> circleSource;
|
||||
circleSource->SetGlyphTypeToCircle();
|
||||
circleSource->SetScale(0.05);
|
||||
circleSource->Update();
|
||||
|
||||
vtkNew<vtkGlyph2D> glyph2D;
|
||||
glyph2D->SetSourceConnection(circleSource->GetOutputPort());
|
||||
glyph2D->SetInputConnection(transformFilter->GetOutputPort());
|
||||
glyph2D->SetColorModeToColorByScalar();
|
||||
glyph2D->Update();
|
||||
|
||||
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(-4.125, 61.375 , 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();
|
||||
}
|
||||
|
||||
// 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.01, lon + 0.01};
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
||||
auto newPointCallBack = vtkSmartPointer<SpawnPointCallback>::New();
|
||||
newPointCallBack->setData(data);
|
||||
newPointCallBack->setPoints(points);
|
||||
newPointCallBack->setRen(ren);
|
||||
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, newPointCallBack);
|
||||
interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, newPointCallBack);
|
||||
interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack);
|
||||
}
|
||||
38
vtk/src/layers/LGlyphLayer.h
Normal file
38
vtk/src/layers/LGlyphLayer.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef LGLYPHLAYER_H
|
||||
#define LGLYPHLAYER_H
|
||||
|
||||
#include "Layer.h"
|
||||
#include "../commands/SpawnPointCallback.h"
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkInteractorStyle.h>
|
||||
|
||||
/** Implements the Layer class for the case of a Lagrangian visualization.
|
||||
* Specifically, this class models the Lagrangian particles in the simulation using the 'glyph' mark and 'transparency' channel to denote age.
|
||||
*/
|
||||
class LGlyphLayer : public Layer {
|
||||
private:
|
||||
vtkSmartPointer<vtkPoints> points;
|
||||
vtkSmartPointer<vtkPolyData> data;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
*/
|
||||
LGlyphLayer();
|
||||
|
||||
/** This function spoofs a few points in the dataset. Mostly used for testing.
|
||||
*/
|
||||
void spoofPoints();
|
||||
|
||||
/** updates the glyphs to reflect the given timestamp in the dataset.
|
||||
* @param t : the time at which to fetch the data.
|
||||
*/
|
||||
void updateData(int t) override;
|
||||
|
||||
vtkSmartPointer<SpawnPointCallback> createSpawnPointCallback();
|
||||
|
||||
void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
16
vtk/src/layers/Layer.cpp
Normal file
16
vtk/src/layers/Layer.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "Layer.h"
|
||||
#include <vtkRenderWindow.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
vtkSmartPointer<vtkRenderer> Layer::getLayer() {
|
||||
return this->ren;
|
||||
}
|
||||
|
||||
void Layer::updateData(int t) {
|
||||
}
|
||||
|
||||
void Layer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
||||
// By default, do nothing.
|
||||
}
|
||||
32
vtk/src/layers/Layer.h
Normal file
32
vtk/src/layers/Layer.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef LAYER_H
|
||||
#define LAYER_H
|
||||
|
||||
#include <vtkInteractorStyle.h>
|
||||
#include <vtkRenderer.h>
|
||||
|
||||
/** This class represents one abstract layer to be rendered to VTK.
|
||||
* It exists to manage multiple different layers under the Program class.
|
||||
*/
|
||||
class Layer {
|
||||
protected:
|
||||
vtkSmartPointer<vtkRenderer> ren;
|
||||
|
||||
public:
|
||||
/** gets the vtkRenderer to assign it to the vtkRenderWindow of the program class.
|
||||
* @return pointer to the vtkRenderer of this class.
|
||||
*/
|
||||
virtual vtkSmartPointer<vtkRenderer> getLayer();
|
||||
|
||||
|
||||
/** updates the data in the layer to reflect the given timestamp.
|
||||
* @param t : the timestamp which the data should reflect.
|
||||
*/
|
||||
virtual void updateData(int t);
|
||||
|
||||
/** Adds an observer to the renderWindowinteractor within which this layer is active.
|
||||
* @param interactor : pointer to the interactor that observers can be added to.
|
||||
*/
|
||||
virtual void addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor);
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user