renamed and stuff
This commit is contained in:
62
particle-track-and-trace/src/layers/BackgroundImage.cpp
Normal file
62
particle-track-and-trace/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
particle-track-and-trace/src/layers/BackgroundImage.h
Normal file
37
particle-track-and-trace/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
|
||||
109
particle-track-and-trace/src/layers/EGlyphLayer.cpp
Normal file
109
particle-track-and-trace/src/layers/EGlyphLayer.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#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 <vtkArrowSource.h>
|
||||
#include "../CartographicTransformation.h"
|
||||
#include "../advection/readdata.h"
|
||||
#include "../advection/interpolate.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
EGlyphLayer::EGlyphLayer(std::shared_ptr<UVGrid> uvGrid) {
|
||||
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
||||
this->ren->SetLayer(1);
|
||||
this->ren->InteractiveOff();
|
||||
|
||||
this->uvGrid = uvGrid;
|
||||
|
||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||
this->direction = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
this->direction->SetName("direction");
|
||||
readCoordinates();
|
||||
}
|
||||
|
||||
|
||||
void EGlyphLayer::readCoordinates() {
|
||||
vtkNew<vtkPoints> points;
|
||||
this->numLats = uvGrid->lats.size();
|
||||
this->numLons = uvGrid->lons.size();
|
||||
|
||||
this->direction->SetNumberOfComponents(3);
|
||||
this->direction->SetNumberOfTuples(numLats * numLons);
|
||||
points->Allocate(numLats * numLons);
|
||||
|
||||
auto camera = createNormalisedCamera();
|
||||
ren->SetActiveCamera(camera);
|
||||
|
||||
int i = 0;
|
||||
int latIndex = 0;
|
||||
for (double lat: uvGrid->lats) {
|
||||
int lonIndex = 0;
|
||||
for (double lon: uvGrid->lons) {
|
||||
auto [u, v] = (*uvGrid)[0, latIndex, lonIndex];
|
||||
direction->SetTuple3(i, 5*u, 5*v, 0);
|
||||
points->InsertPoint(i++, lon, lat, 0);
|
||||
lonIndex++;
|
||||
}
|
||||
latIndex++;
|
||||
}
|
||||
this->data->SetPoints(points);
|
||||
this->data->GetPointData()->AddArray(this->direction);
|
||||
this->data->GetPointData()->SetActiveVectors("direction");
|
||||
|
||||
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter(uvGrid);
|
||||
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) {
|
||||
int i = 0;
|
||||
for (int lat = 0; lat < uvGrid->latSize; lat++) {
|
||||
for (int lon = 0; lon < uvGrid->lonSize; lon++) {
|
||||
auto [u, v] = (*uvGrid)[t/3600, lat, lon];
|
||||
// TODO: 5*v scaling stuff should really be a filter transform
|
||||
this->direction->SetTuple3(i, 5*u, 5*v, 0);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
this->direction->Modified();
|
||||
}
|
||||
38
particle-track-and-trace/src/layers/EGlyphLayer.h
Normal file
38
particle-track-and-trace/src/layers/EGlyphLayer.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef EGLYPHLAYER_H
|
||||
#define EGLYPHLAYER_H
|
||||
|
||||
#include "Layer.h"
|
||||
#include <vtkPolyData.h>
|
||||
|
||||
#include "../advection/UVGrid.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;
|
||||
std::shared_ptr<UVGrid> uvGrid;
|
||||
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(std::shared_ptr<UVGrid> uvGrid);
|
||||
|
||||
/** 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
|
||||
101
particle-track-and-trace/src/layers/LGlyphLayer.cpp
Normal file
101
particle-track-and-trace/src/layers/LGlyphLayer.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#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);
|
||||
newPointCallBack->setUVGrid(uvGrid);
|
||||
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(std::shared_ptr<UVGrid> uvGrid, std::unique_ptr<AdvectionKernel> advectionKernel) {
|
||||
this->ren = vtkSmartPointer<vtkRenderer>::New();
|
||||
this->ren->SetLayer(2);
|
||||
|
||||
this->points = vtkSmartPointer<vtkPoints>::New();
|
||||
this->data = vtkSmartPointer<vtkPolyData>::New();
|
||||
this->data->SetPoints(this->points);
|
||||
|
||||
advector = std::move(advectionKernel);
|
||||
this->uvGrid = uvGrid;
|
||||
|
||||
auto camera = createNormalisedCamera();
|
||||
ren->SetActiveCamera(camera);
|
||||
|
||||
vtkSmartPointer<vtkTransformFilter> transformFilter = createCartographicTransformFilter(uvGrid);
|
||||
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();
|
||||
}
|
||||
|
||||
void LGlyphLayer::updateData(int t) {
|
||||
const int SUPERSAMPLINGRATE = 4;
|
||||
double point[3];
|
||||
for (vtkIdType n = 0; n < this->points->GetNumberOfPoints(); n++) {
|
||||
this->points->GetPoint(n, point);
|
||||
for (int i = 0; i < SUPERSAMPLINGRATE; i++) {
|
||||
std::tie(point[1], point[0]) = advector->advect(t, point[1], point[0], (t-lastT)/SUPERSAMPLINGRATE);
|
||||
}
|
||||
this->points->SetPoint(n, point[0], point[1], 0);
|
||||
}
|
||||
lastT = t;
|
||||
this->points->Modified();
|
||||
}
|
||||
|
||||
void LGlyphLayer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
||||
auto newPointCallBack = createSpawnPointCallback();
|
||||
interactor->AddObserver(vtkCommand::LeftButtonPressEvent, newPointCallBack);
|
||||
interactor->AddObserver(vtkCommand::LeftButtonReleaseEvent, newPointCallBack);
|
||||
interactor->AddObserver(vtkCommand::MouseMoveEvent, newPointCallBack);
|
||||
}
|
||||
40
particle-track-and-trace/src/layers/LGlyphLayer.h
Normal file
40
particle-track-and-trace/src/layers/LGlyphLayer.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef LGLYPHLAYER_H
|
||||
#define LGLYPHLAYER_H
|
||||
|
||||
#include "Layer.h"
|
||||
#include "../advection/AdvectionKernel.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;
|
||||
std::unique_ptr<AdvectionKernel> advector;
|
||||
std::shared_ptr<UVGrid> uvGrid;
|
||||
int lastT = 1000;
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
*/
|
||||
LGlyphLayer(std::shared_ptr<UVGrid> uvGrid, std::unique_ptr<AdvectionKernel> advectionKernel);
|
||||
|
||||
/** 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
|
||||
17
particle-track-and-trace/src/layers/Layer.cpp
Normal file
17
particle-track-and-trace/src/layers/Layer.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "Layer.h"
|
||||
#include <vtkRenderWindow.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
vtkSmartPointer<vtkRenderer> Layer::getLayer() {
|
||||
return this->ren;
|
||||
}
|
||||
|
||||
void Layer::updateData(int t) {
|
||||
// By default, do nothing
|
||||
}
|
||||
|
||||
void Layer::addObservers(vtkSmartPointer<vtkRenderWindowInteractor> interactor) {
|
||||
// By default, do nothing
|
||||
}
|
||||
32
particle-track-and-trace/src/layers/Layer.h
Normal file
32
particle-track-and-trace/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 observers 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