I'm trying to read a legacy .vtk file in c++ and populate my data structures using vtkGenericDataObjectReader (for a Molecular Dynamics simulation). I've searched through the documentation and incorporated answers from similar SO questions, but I'm still misunderstanding something. Here's the file. Forgive the binary, I think it's written correctly but I wouldn't rule out it as the problem.
# vtk DataFile Version 3.0
vtk output
BINARY
DATASET POLYDATA
FIELD FieldData 2
TIME 1 1 double
\00\00\00\00\00\00\00\00CYCLE 1 1 int
\00\00\00\00POINTS 8 double
\BF\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2\BF\F0\ED\E4m \D3B2?\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2\BF\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2?\F0\ED\E4m\D3B2VERTICES 8 16
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00POINT_DATA 8
SCALARS mass double
LOOKUP_TABLE default
#H\00\00\00\00\00\00#H\00\00\00\00\00\00#H\00\00\00\00\00\00#H\00\00\00\00\00\00#H\00\00\00\00\00\00#H\00\00\00\00\00\00#H\00\00\00\00\00\00#H\00\00\00\00\00\00VECTORS velocity double
\BF\C0\9E b\D8_\BFp\B4Mz\8B\BF\C1\A3|9?\B5\81`\FA\CAk?\C7N\A4ig\BF\94\E5R,\BE瀿\C5wSbK\8E?\98l?\E0\AFϿ\CC3\81\EE\F1n*\BF\C3\DA6\EArf?\B5Ж\CD\EF\99?\C1\F1,\9E\F3\CF?\99=Aɕm"?\B2\87l\89\96eU?\A9\E9cA\A4[?\BD\D6\FD\A2Ϳ\C5\E9r}\93\B1\BF\B8X:a\B86\A4?\BDB\CE\DBV֓\BF\A4\AAa,~,?Č7\CCR{?\BC\F4\99L\B7Y\BF\C3\CD W\E4v(?\BFOS\D4f\8B
This is my code. It segfaults in vtkDataReader::ReadString(char*) from /usr/lib/libvtkIO.so.5.8 while trying to execute the line 'int rv = reader->ReadPoints(ps, int(num_particles));'
vtkSmartPointer<vtkGenericDataObjectReader> reader =
vtkSmartPointer<vtkGenericDataObjectReader>::New();
reader->SetFileName(in_rel_path.c_str());
reader->Update();
vtkPolyData* output = reader->GetPolyDataOutput();
vtkPointSet *ps = NULL;
size_t num_particles = output->GetNumberOfPoints();
int rv = reader->ReadPoints(ps, int(num_particles));
vtkPointData* pd = output->GetPointData();
vtkDoubleArray* vel_data = vtkDoubleArray::SafeDownCast(pd->GetVectors());
vtkDoubleArray* mass_data = vtkDoubleArray::SafeDownCast(pd->GetScalars());
vtkDoubleArray* time_data = vtkDoubleArray::SafeDownCast(pd->GetArray("TIME"));
vtkIntArray* cycle_data = vtkIntArray::SafeDownCast(pd->GetArray("CYCLE"));
tot_iters = cycle_data->GetValue(0);
particles.resize(0);
double* position = new double[3];
double* velocity = new double[3];
for( size_t i = 0; i < num_particles; i++ )
{
ps->GetPoint(int(i), position);
vel_data->GetTupleValue(int(i), velocity);
double pmass = mass_data->GetValue(int(i));
particles.push_back(Particle(vec3(position[0],position[1],position[2]),
vec3(velocity[0],velocity[1],velocity[2]),
pmass));
}
delete[] position;
delete[] velocity;
I admit I don't know much about VTK. If anyone can help explain what I'm doing wrong, or a better way to go about this, I'd really appreciate it.
The best option to read a PolyData is using the vtkPolyDataReader class.
But if you read the class documentation they give the following warning about BINARY files
"Binary files written on one system may not be readable on other systems."
Here is an example, taken from VTK Wiki that reads .vtk file
#include <vtkPolyDataReader.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
int main ( int argc, char *argv[] )
{
// Parse command line arguments
if(argc != 2)
{
std::cerr << "Usage: " << argv[0]
<< " Filename(.vtk)" << std::endl;
return EXIT_FAILURE;
}
std::string filename = argv[1];
// Read all the data from the file
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
// Visualize
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->SetBackground(.3, .6, .3); // Background color green
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
Related
TL;DR
I have a pipeline which reads an image and displays a mesh using VTK; upon changing the input to the image reader and updating the pipeline, the mesh doesn't update until I interact with the window.
The Long Version
I have a directory with a sequence of segmentation files (i.e., 3D image volumes where pixel values correspond to structures in a corresponding image) which show how a structure changes over time. I've written a utility in VTK which allows me to load the first image in the directory, visualize a label as a mesh, and "step" forwards or backwards using the arrow keys by changing the file name of the input image and updating the pipeline. This very nearly works--the only issue is that, after updating the pipeline, the meshes don't update until I interact with the window (simply clicking anywhere in the window causes the mesh to update, for example).
What I've Tried:
Calling Update() on the reader:
this->reader->Update();
Calling Modified() on the actors:
const auto actors = this->GetCurrentRenderer()->GetActors();
actors->InitTraversal();
for (vtkIdType i = 0; i < actors->GetNumberOfItems(); ++i)
{
actors->GetNextActor()->Modified();
}
Calling Render() on the current render window:
this->GetCurrentRenderer()->Render();
MCVE:
NOTE: the reader is updated in KeyPressInteractorStyle::UpdateReader().
// VTK
#include <vtkSmartPointer.h>
#include <vtkNIFTIImageReader.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkDiscreteMarchingCubes.h>
#include <vtkProperty.h>
#include <vtkInteractorStyleTrackballCamera.h>
// Define interaction style
class KeyPressInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
static KeyPressInteractorStyle* New();
vtkTypeMacro(KeyPressInteractorStyle, vtkInteractorStyleTrackballCamera);
virtual void OnKeyPress()
{
// Get the keypress
vtkRenderWindowInteractor *rwi = this->Interactor;
std::string key = rwi->GetKeySym();
// Output the key that was pressed
std::cout << "Pressed " << key << std::endl;
// Handle an arrow key
if(key == "Down" || key == "Right")
{
this->index += 1;
this->UpdateReader();
}
// Handle an arrow key
if(key == "Up" || key == "Left")
{
this->index -= 1;
this->UpdateReader();
}
// Forward events
vtkInteractorStyleTrackballCamera::OnKeyPress();
}
void UpdateReader()
{
std::cout << "Frame: " << this->index << std::endl;
const auto fn = this->directory + std::to_string(this->index) + ".nii.gz";
std::cout << fn << std::endl;
this->reader->SetFileName( fn.c_str() );
this->reader->Update();
const auto actors = this->GetCurrentRenderer()->GetActors();
actors->InitTraversal();
for (vtkIdType i = 0; i < actors->GetNumberOfItems(); ++i)
{
actors->GetNextActor()->Modified();
}
this->GetCurrentRenderer()->Render();
}
unsigned int index = 0;
std::string directory;
vtkSmartPointer<vtkNIFTIImageReader> reader;
};
vtkStandardNewMacro(KeyPressInteractorStyle);
int
main( int argc, char ** argv )
{
std::string dn = argv[1];
const auto renderer = vtkSmartPointer<vtkRenderer>::New();
unsigned int frameid = 0;
const auto reader = vtkSmartPointer<vtkNIFTIImageReader>::New();
reader->SetFileName( (dn + std::to_string(frameid) + ".nii.gz").c_str() );
const auto cubes = vtkSmartPointer<vtkDiscreteMarchingCubes>::New();
cubes->SetInputConnection( reader->GetOutputPort() );
cubes->SetValue( 0, 1 );
const auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection( cubes->GetOutputPort() );
mapper->ScalarVisibilityOff();
const auto actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper( mapper );
renderer->AddActor( actor );
const auto window = vtkSmartPointer<vtkRenderWindow>::New();
window->AddRenderer( renderer );
const auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
const auto style = vtkSmartPointer<KeyPressInteractorStyle>::New();
style->reader = reader;
style->directory = dn;
interactor->SetInteractorStyle( style );
style->SetCurrentRenderer( renderer );
interactor->SetRenderWindow( window );
window->Render();
interactor->Start();
return EXIT_SUCCESS;
}
You have actually not tried to call Render() on the current render window, you are calling it on the current renderer, which are two different things. As the documentation of vtkRenderer::Renderer() states,
CALLED BY vtkRenderWindow ONLY.
End-user pass your way and call vtkRenderWindow::Render(). Create an
image. This is a superclass method which will in turn call the
DeviceRender method of Subclasses of vtkRenderer.
So change this->GetCurrentRenderer()->Render(); to this->GetCurrentRenderer()->GetRenderWindow()->Render();
I am using vtk library with C++ to generate and visualize some synthetic voxel data with given color and transparency mapping. An example is shown below:
As shown in the figure, the data is 3D in general, and it works great. However, in specific cases when the data becomes 2D, the visualization windows shows nothing.
I am posting few lines of my code which may be helpful.
imageData = vtkSmartPointer<vtkImageData>::New();
imageData->SetDimensions(X1, X2, X3); //For 2D, one of X1,X2 & X3=1
imageData->AllocateScalars(VTK_INT, 1);
int* I = new int[X1X2X3](); //int X1X2X3 = X1*X2*X3
I = static_cast<int*>(imageData->GetScalarPointer());
Please note that for 2D, either X1=1 or X2=1 or X3=1.
Any suggestions?
EDIT:
I am adding an equivalent code, which will demonstrate the exact problem I am facing:
main.cpp
//#include <vtkAutoInit.h> // if not using CMake to compile, necessary to use this macro
//#define vtkRenderingCore_AUTOINIT 3(vtkInteractionStyle, vtkRenderingFreeType, vtkRenderingOpenGL2)
//#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL2)
//#define vtkRenderingContext2D_AUTOINIT 1(vtkRenderingContextOpenGL2)
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkVolumeProperty.h>
#include <vtkSampleFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkImageData.h>
#include <stdlib.h>
using namespace std;
int main()
{
//Declaring Variables
vtkSmartPointer<vtkImageData> imageData;
vtkSmartPointer<vtkVolumeProperty> volumeProperty;
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity;
vtkSmartPointer<vtkColorTransferFunction> color;
vtkSmartPointer<vtkVolume> volume;
vtkSmartPointer<vtkSmartVolumeMapper> mapper;
vtkSmartPointer<vtkActor> actor;
vtkSmartPointer<vtkRenderer> renderer;
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor;
vtkSmartPointer<vtkRenderWindow> renderWindow;
int* I;
int X1, X2, X3, X1X2X3;
//Assigning Values , Allocating Memory
X1 = 10;
X2 = 10;
X3 = 10;
X1X2X3 = X1*X2*X3;
I = new int[X1X2X3]();
imageData = vtkSmartPointer<vtkImageData>::New();
volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
color = vtkSmartPointer<vtkColorTransferFunction>::New();
volume = vtkSmartPointer<vtkVolume>::New();
mapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
actor = vtkSmartPointer<vtkActor>::New();
renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
volumeProperty->ShadeOff();
volumeProperty->SetInterpolationType(0);
volumeProperty->SetColor(color);
volumeProperty->SetScalarOpacity(compositeOpacity);
imageData->SetDimensions(X1, X2, X3);
imageData->AllocateScalars(VTK_INT, 1);
I = static_cast<int*>(imageData->GetScalarPointer());
renderWindow->AddRenderer(renderer);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->SetBackground(0.5, 0.5, 0.5);
renderWindow->SetSize(800, 800);
mapper->SetBlendModeToComposite();
imageData->UpdateCellGhostArrayCache();
mapper->SetRequestedRenderModeToRayCast();
mapper->SetInputData(imageData);
volume->SetMapper(mapper);
volume->SetProperty(volumeProperty);
renderer->AddViewProp(volume);
volumeProperty->ShadeOff();
//Setting Voxel Data and Its Properties
for (int i = 0; i < X1X2X3; i++)
{
I[i] = i;
compositeOpacity->AddPoint(i, 1);
color->AddRGBPoint(i, double( rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX);
}
renderer->ResetCamera();
renderWindow->Render();
renderWindowInteractor->Start();
getchar();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(EvoSim)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_USE_RELATIVE_PATHS ON)
#GRABBING VTK
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(MAIN main.cpp)
target_link_libraries(MAIN ${VTK_LIBRARIES})
This leads to an output like below (for, X1=X2=X3=10)
However if I make X1=1, the output window is empty.
EDIT:
I just observed that the number of voxels along a certain dimension, displayed on the screen are always one less than the maximum number of voxels in that dimensions. For example, if X1=X2=X3=10, the number of voxels in each dimensions which are displayed on vtkwindow is 9. This is not what I would expect. I think this is the problem with X1=1, which makes 1-1=0 voxel display.
Any suggestions??
This remained unanswered for long. So I am adding my solution/workaround.
I had to add an extra dummy layer in each dimension of imagedata. [See this line in the code imageData->SetDimensions(X1 +1 , X2 + 1, X3 + 1);]. Rest is self explanatory.
#pragma once
//#include <vtkAutoInit.h> // if not using CMake to compile, necessary to use this macro
//#define vtkRenderingCore_AUTOINIT 3(vtkInteractionStyle, vtkRenderingFreeType, vtkRenderingOpenGL2)
//#define vtkRenderingVolume_AUTOINIT 1(vtkRenderingVolumeOpenGL2)
//#define vtkRenderingContext2D_AUTOINIT 1(vtkRenderingContextOpenGL2)
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartVolumeMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkVolumeProperty.h>
#include <vtkSampleFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkImageData.h>
#include <stdlib.h>
#include <numeric> // std::iota
using namespace std;
int main()
{
//Declaring Variables
vtkSmartPointer<vtkImageData> imageData;
vtkSmartPointer<vtkVolumeProperty> volumeProperty;
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity;
vtkSmartPointer<vtkColorTransferFunction> color;
vtkSmartPointer<vtkVolume> volume;
vtkSmartPointer<vtkSmartVolumeMapper> mapper;
vtkSmartPointer<vtkActor> actor;
vtkSmartPointer<vtkRenderer> renderer;
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor;
vtkSmartPointer<vtkRenderWindow> renderWindow;
int X1, X2, X3, X1X2X3;
//Assigning Values , Allocating Memory
X1 = 10;
X2 = 10;
X3 = 10;
X1X2X3 = X1*X2*X3;
imageData = vtkSmartPointer<vtkImageData>::New();
imageData->SetDimensions(X1 + 1, X2 + 1, X3 + 1);
imageData->AllocateScalars(VTK_INT, 1);
volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
color = vtkSmartPointer<vtkColorTransferFunction>::New();
volume = vtkSmartPointer<vtkVolume>::New();
mapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
actor = vtkSmartPointer<vtkActor>::New();
renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
volumeProperty->ShadeOff();
volumeProperty->SetInterpolationType(0);
volumeProperty->SetColor(color);
volumeProperty->SetScalarOpacity(compositeOpacity);
imageData->AllocateScalars(VTK_INT, 1);
renderWindow->AddRenderer(renderer);
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->SetBackground(0.5, 0.5, 0.5);
renderWindow->SetSize(800, 800);
mapper->SetBlendModeToComposite();
imageData->UpdateCellGhostArrayCache();
mapper->SetRequestedRenderModeToRayCast();
mapper->SetInputData(imageData);
volume->SetMapper(mapper);
volume->SetProperty(volumeProperty);
renderer->AddViewProp(volume);
volumeProperty->ShadeOff();
//I is supposed to store the 3D data which has to be shown as volume visualization. This 3D data is stored
//as a 1D array in which the order of iteration over 3 dimensions is x->y->z, this leads to the following
//3D to 1D index conversion farmula index1D = i + X1*j + X1*X2*k
vector<int> I(X1X2X3,0); // No need to use int* I = new int[X1X2X3] //Vectors are good
std::iota(&I[0], &I[0] + X1X2X3, 1); //Creating dummy data as 1,2,3...X1X2X3
//Setting Voxel Data and Its Properties
for (int k = 0; k < X3 + 1 ; k++)
{
for (int j = 0; j < X2 + 1 ; j++)
{
for (int i = 0; i < X1 + 1 ; i++)
{
int* voxel = static_cast<int*>(imageData->GetScalarPointer(i, j, k));
if (i==X1 || j== X2 || k==X3)
{
//Assigning zeros to dummy voxels, these will not be displayed anyways
voxel[0] = 0;
}
else
{
//copying data from I to imagedata voxel
voxel[0] = I[i + X1*j + X1*X2*k];
}
}
}
}
//Setting Up Display Properties
for (int i = 1; i < X1X2X3; i++)
{
compositeOpacity->AddPoint(i, 1);
color->AddRGBPoint(i, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, double(rand()) / RAND_MAX);
}
renderer->ResetCamera();
renderWindow->Render();
renderWindowInteractor->Start();
getchar();
return 0;
}
Now the expected number of voxels in each dimensions (10 as per the code above), are correctly seen
Intention
I wrote a VTK application that generates a spiral using vtkPoints > vtkPolyLine > vtkPolyData > vtkPolyDataMapper and displays it. This works fine, if done static at the initialization of the program.
Now, I want to add new data points dynamically. The intention is to visualize measurements in real time, so new data will be added in certain intervals.
Issues
Currently, I just implemented a TimerEvent to update the vtkPoints and vtkPolyLine. But, the program just shows the static data generated before the vtkRenderWindowInteractor was started. I also tried to use "Modified()" and "Update()" calls to nearly all objects, tried to remove, regenerate and add a new actor to the renderer -- but without success! I added my C++ code below...
Related-Questions
The following mailing list question is about this issues, but the solution given doen't work for me:
http://public.kitware.com/pipermail/vtkusers/2006-November/038377.html
The following question seems to be related, but there are no useful answers:
VTK: update data points in renderWindow at every simulation timestep
Questions
How to tell VTK that the vtkPolyData object has changed?
Which of the VTK UsersGuide should I probably have a closer look at?
Details / Source Code
I'm using Visual Studio Community 2017 and VTK 8.0.0, both compiled as Win32 target.
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
int numOfPoints = 0;
double t = 0;
void NextPoint() {
double x = t * cos(t);
double y = t * sin(t);
points->InsertNextPoint(x, y, t);
polyLine->GetPointIds()->InsertNextId(numOfPoints);
numOfPoints++;
t += 0.1;
}
vtkSmartPointer<vtkPolyData> generateEllipse() {
// Add some points so we actually see something at all...
for (int i = 0; i < 100; ++i) {
NextPoint();
}
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyLine);
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
polyData->SetLines(cells);
return polyData;
}
class vtkTimerCallback : public vtkCommand
{
public:
static vtkTimerCallback *New()
{
vtkTimerCallback *cb = new vtkTimerCallback;
cb->TimerCount = 0;
return cb;
}
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
void *vtkNotUsed(callData))
{
if (vtkCommand::TimerEvent == eventId)
{
NextPoint(); // Add another point to polyData
++this->TimerCount;
cout << this->TimerCount << endl;
}
}
private:
int TimerCount;
};
int main(int argc, char** argv) {
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(renderWindow);
vtkSmartPointer<vtkPolyData> data = generateEllipse();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(data);
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(255, 255, 0);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->ResetCamera();
renderWindow->Render();
// Add Timer Event...
rwi->Initialize();
vtkSmartPointer<vtkTimerCallback> cb = vtkSmartPointer<vtkTimerCallback>::New();
rwi->AddObserver(vtkCommand::TimerEvent, cb);
int timerId = rwi->CreateRepeatingTimer(100); // every 100ms
std::cout << "timerId: " << timerId << std::endl;
// Start Displaying...
rwi->Start();
return 0;
}
the problem is that the cells are not stored by pointer - when you call cells->InsertNextCell(polyLine); the data is copied, not pointed to, in order to create an efficient storage of the cells in an array (the whole implementation is actually in the header of vtkCellArray so you can check it out). So then when you update polyLine, it has no effect in the polydata, because the polydata have their own copy that you did not update. The following code works for me (you have to expose the polydata and the cellArray):
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
void *vtkNotUsed(callData))
{
if (vtkCommand::TimerEvent == eventId)
{
NextPoint(); // Add another point to polyData
cells->Initialize(); // reset the cells to remove the old spiral
cells->InsertNextCell(polyLine); // re-insert the updated spiral
cells->Modified(); // required to update
data->Modified(); // required to update
++this->TimerCount;
cout << polyLine->GetNumberOfPoints() << endl;
renderWindow->Render(); // refresh the render window after each update
}
}
Yesterday I worked out an alternative solution using a vtkProgrammableDataObjectSource as DataSource. Tomj's solution is the more direct and simple solution... However, there is no C++ Example Code at vtk.org that explains how to use vtkProgrammableDataObjectSource and I had to work it out by trial and error. So I'll post it here, as it might help others:
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
#include <vtkProgrammableFilter.h>
#include <vtkCallbackCommand.h>
#include <vtkPolyDataStreamer.h>
#include <vtkProgrammableDataObjectSource.h>
vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS = vtkSmartPointer<vtkProgrammableDataObjectSource>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
int numOfPoints = 0;
double t = 0;
void NextPoint() {
double x = t * cos(t);
double y = t * sin(t);
points->InsertNextPoint(x, y, t);
polyLine->GetPointIds()->InsertNextId(numOfPoints);
numOfPoints++;
t += 0.1;
}
void generateEllipse(void *caller) {
vtkProgrammableDataObjectSource *pDOS = vtkProgrammableDataObjectSource::SafeDownCast((vtkObjectBase*)caller);
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyLine);
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
polyData->SetLines(cells);
pDOS->SetOutput(polyData);
}
int counter2 = 0;
void TimerCallbackFunction(vtkObject* caller, long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) {
cout << "timer callback: " << counter2 << endl;
// To avoid globals we can implement this later...
// vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS =
// static_cast<vtkProgrammableDataObjectSource*>(clientData);
vtkRenderWindowInteractor *rwi =
static_cast<vtkRenderWindowInteractor*>(caller);
NextPoint();
pDOS->Modified();
rwi->Render();
renderer->ResetCamera(); // Optional: Reposition Camera, so it displays the whole object
counter2++;
}
int main(int argc, char** argv) {
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(renderWindow);
pDOS->SetExecuteMethod(&generateEllipse, pDOS);
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(pDOS->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(255, 255, 0);
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->ResetCamera();
renderWindow->Render();
// Add Timer Event...
vtkSmartPointer<vtkCallbackCommand> timerCallback = vtkSmartPointer<vtkCallbackCommand>::New();
timerCallback->SetCallback(TimerCallbackFunction);
rwi->Initialize();
rwi->CreateRepeatingTimer(100);
rwi->AddObserver(vtkCommand::TimerEvent, timerCallback);
// Start Displaying...
rwi->Start();
return 0;
}
Solved: cxx file below is working as expected now. Thanks to #tomj as I used his ideas as well.
I have a data file (.vtk) file from which I read unstructured grid. How can I display cell attributes as labels?
cxx:
#include <vtkLookupTable.h>
#include <vtkCellData.h>
#include <vtkSmartPointer.h>
#include <vtkActor2D.h>
#include <vtkProperty.h>
#include <vtkDataSetMapper.h>
#include <vtkLabeledDataMapper.h>
#include <vtkUnstructuredGridReader.h>
#include <vtkUnstructuredGrid.h>
#include <vtkUnstructuredGridGeometryFilter.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include "vtkIdFilter.h"
#include "vtkCellCenters.h"
#include <iostream>
int main(int argc, char* argv[])
{
std::string inputFilename = argv[1];
// read file.
vtkSmartPointer<vtkUnstructuredGridReader> reader = vtkSmartPointer<vtkUnstructuredGridReader>::New();
reader->SetFileName(inputFilename.c_str());
reader->ReadAllScalarsOn();
reader->SetScalarsName(reader->GetScalarsNameInFile(0));
reader->Update();
unsigned int ncell = reader->GetOutput()->GetNumberOfCells();
// get attributes.
vtkSmartPointer<vtkUnstructuredGrid> ugrid = reader->GetOutput();
vtkSmartPointer<vtkCellData> cellData = ugrid->GetCellData();
vtkSmartPointer<vtkDataArray> data = cellData->GetScalars(reader->GetScalarsNameInFile(0));
// validate that attributes are read correctly.
for (int i=0; i<ncell; i++)
{
std::cout<< i << ": " << data->GetComponent(i,0)<< std::endl;
}
data = cellData->GetScalars(reader->GetScalarsNameInFile(1));
for (int i=0; i<ncell; i++)
{
std::cout<< i << ": " << data->GetComponent(i,0)<< std::endl;
}
data = cellData->GetScalars(reader->GetScalarsNameInFile(0));
// geometry filter.
vtkSmartPointer<vtkUnstructuredGridGeometryFilter> geometryFilter = vtkSmartPointer<vtkUnstructuredGridGeometryFilter>::New();
geometryFilter->SetInputConnection(reader->GetOutputPort());
geometryFilter->Update();
// Generate data arrays containing point and cell ids
vtkSmartPointer<vtkIdFilter> ids = vtkSmartPointer<vtkIdFilter>::New();
ids->SetInputConnection(geometryFilter->GetOutputPort());
ids->PointIdsOff();
ids->CellIdsOff();
ids->FieldDataOn();
// Create labels for cells
vtkSmartPointer<vtkCellCenters> cc = vtkSmartPointer<vtkCellCenters>::New();
cc->SetInputConnection(ids->GetOutputPort());
// lut
vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
lut->SetNumberOfTableValues(ncell);
lut->Build();
lut->SetTableValue(0, 1, 0, 0, 1); // red.
lut->SetTableValue(1, 0, 1, 0, 1); // green.
lut->SetTableValue(2, 0, 0, 1, 1); // blue.
// mapper.
vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
mapper->SetInputConnection(geometryFilter->GetOutputPort());
mapper->SetLookupTable(lut);
mapper->SetScalarVisibility(1);
mapper->SetScalarModeToUseCellData();
mapper->SetScalarRange(11, 13);
mapper->GetInput()->GetCellData()->SetActiveScalars("cell_tag");
// label mapper.
vtkSmartPointer<vtkLabeledDataMapper> label_mapper = vtkSmartPointer<vtkLabeledDataMapper>::New();
label_mapper->SetInputConnection(cc->GetOutputPort());
label_mapper->SetLabelModeToLabelScalars();
// actor.
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetRepresentationToWireframe();
// label actor.
vtkSmartPointer<vtkActor2D> label_actor = vtkSmartPointer<vtkActor2D>::New();
label_actor->SetMapper(label_mapper);
// renderer.
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->AddActor(label_actor);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
Datafile (.vtk):
# vtk DataFile Version 3.0
All in VTK format
ASCII
DATASET UNSTRUCTURED_GRID
POINTS 8 float
-20 0 0
-12.898 0 0
-7.65367 18.4776 0
-14.1421 14.1421 0
-18.4776 7.65367 0
-11.8832 4.95205 0
-9.03623 9.14123 0
-4.79931 11.937 0
CELLS 3 15
4 0 1 5 4
4 4 5 6 3
4 3 6 7 2
CELL_TYPES 3
9
9
9
CELL_DATA 3
SCALARS oga_cell_type int 1
LOOKUP_TABLE default
5
6
7
SCALARS cell_tag int 1
LOOKUP_TABLE default
11
12
13
Output:
See for example this tutorial, but it pretty much boils down to this:
mapper->SetLookupTable(lut); // lut is a lookup table for colors, see the linked tutorial or other vtk tutorials about look up tables
mapper->SetScalarVisibility(1);
mapper->SetScalarModeToUseCellData();
mapper->GetInput()->GetCellData()->SetActiveScalars("nameOfTheArrayToUseForColoringTheCells");
I'm developing a 3D environment using VC++ and OSG and I need some help
I'm using this code below to charge the 3D models for the scene
mueble00Node = osgDB::readNodeFile("Model/mueble_desk.3ds");
mueble00Transform = new osg::MatrixTransform;
mueble00Transform->setName("mueble00");
mueble00Transform->setDataVariance(osg::Object::STATIC);
mueble00Transform->addChild(mueble00Node);
sceneRoot->addChild(mueble00Transform);
I've tried with some lines to rotate the 3D models, but with no result
Could anybody explain to me how to rotate the models on its own axis?
Use MatrixTransform::setMatrix() to change the orientation of the child node.
MatrixTransform* transform = new osg::MatrixTransform;
const double angle = 0.8;
const Vec3d axis(0, 0, 1);
transform->setMatrix(Matrix::rotate(angle, axis));
Below is a complete program that loads and displays a 3D object with and without the transformation added.
#include <string>
#include <osg/Object>
#include <osg/Node>
#include <osg/Transform>
#include <osg/Matrix>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
using namespace osg;
int main(int argc, char** argv)
{
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << "<file>\n";
exit(1);
}
const std::string file = argv[1];
// Load a node.
Node* node = osgDB::readNodeFile(file);
if (!node) {
std::cerr << "Can't load node from file '" << file << "'\n";
exit(1);
}
// Set a transform for the node.
MatrixTransform* transform = new osg::MatrixTransform;
const double angle = 0.8;
const Vec3d axis(0, 0, 1);
transform->setMatrix(Matrix::rotate(angle, axis));
transform->setName(file);
transform->addChild(node);
// Add the node with and without the transform.
Group* scene = new Group();
scene->addChild(transform);
scene->addChild(node);
// Start a scene graph viewer.
osgViewer::Viewer viewer;
viewer.setSceneData(scene);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
viewer.realize();
while (!viewer.done()) viewer.frame();
}
You'll want to use a quat
http://www.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00568.html
It has a number of functions you can use for rotation.