renamed and stuff

This commit is contained in:
robin
2024-05-06 16:45:56 +02:00
parent 3c64364482
commit 59bd2f5a73
35 changed files with 35 additions and 35 deletions

View 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();
}

View 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

View 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();
}

View 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

View 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);
}

View 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

View 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
}

View 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