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");
Related
I am trying to use libxlsxwriter to insert images in a column row by row but the images are out of cell bound and on top of each other.
Edit:
I found that this line of code might be causing some issues worksheet_set_default_row(worksheet,110,true);
and changed my code to the following:
#include <QCoreApplication>
#include "QProcess"
#include "QThread"
#include "xlsxwriter.h"
#include <QtGui/QImage>
#include <QBuffer>
#include<QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QImage* img = new QImage("F:/Muaz/Programming/Visual C++/Qt/web_browser_open_close/Image0004.jpg");
int pixel_width = int(25 * 7 + 0.5) + 5;
int pixel_height = int(4.0 / 3.0 * 110);
QImage scaled_img =img->scaled(pixel_width,pixel_height,Qt::KeepAspectRatio);
int new_h = scaled_img.height();
int new_w = scaled_img.width();
QByteArray sbytes;
QBuffer buffer(&sbytes);
buffer.open(QIODevice::WriteOnly);
scaled_img.save(&buffer, "jpg");
buffer.close();
unsigned char* data =new unsigned char[sbytes.size()];
memcpy(data,sbytes.constData(),sbytes.size());
QImage* img1 = new QImage("F:/Muaz/Programming/Visual C++/Qt/web_browser_open_close/Image0003.jpg");
QImage scaled_img1 =img1->scaled(pixel_width,pixel_height,Qt::KeepAspectRatio);
qInfo() << "width: " << new_w << ", height: " << new_h;
qInfo() << "width: " << scaled_img1.width() << ", height: " << scaled_img1.height();
QByteArray sbytes1;
QBuffer buffer1(&sbytes1);
buffer1.open(QIODevice::WriteOnly);
scaled_img1.save(&buffer1, "jpg");
buffer1.close();
unsigned char* data1 =new unsigned char[sbytes1.size()];
memcpy(data1,sbytes1.constData(),sbytes1.size());
qInfo() << sbytes.size();
qInfo() << sbytes1.size();
lxw_workbook *workbook = workbook_new("F:/Muaz/Programming/Visual C++/Qt/web_browser_open_close/sample.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "Shop Items");
worksheet_set_row(worksheet,0,110,NULL);
worksheet_set_row(worksheet,1,110,NULL);
worksheet_set_row(worksheet,2,110,NULL);
worksheet_set_row(worksheet,3,110,NULL);
worksheet_set_column(worksheet,1,1,25,NULL);
lxw_image_options lio = {.x_offset = (pixel_width-new_w)/2, .y_offset = (pixel_height-new_h)/2};
worksheet_write_string(worksheet, 0, 0, "Ürün Adı", NULL);
worksheet_insert_image_buffer_opt(worksheet,0,1,data,sbytes.size(), &lio);
worksheet_write_string(worksheet, 1, 0, "Ürün Adı", NULL);
lio = {.x_offset = (pixel_width-scaled_img1.width())/2, .y_offset = (pixel_height-scaled_img1.height())/2};
worksheet_insert_image_buffer_opt(worksheet,1,1,data1,sbytes1.size(), &lio);
worksheet_write_string(worksheet, 2, 0, "Ürün Adı", NULL);
workbook_close(workbook);
return a.exec();
}
Now I get the following output:
The first image appears so small while the second one is slightly below the border line. Why is this?
How to insert the image at the center of the cell and within bounds of the cell width and height? Thanks.
You have to set the dpi to 96 (default for excel and other MS products) so that it is displayed correctly in the position at the correct size.
as QImage does have only set dot per meter i converted inch to meter then set dpm as follows:
QImage img
img.setDotsPerMeterX(3780);
img.setDotsPerMeterY(3780);
Now every thing is working as it should.
I am implementing a DCGAN network in LibTorch/Pytorch. I am following the official example in https://github.com/pytorch/examples/blob/master/cpp/dcgan/dcgan.cpp .
The only differences between my problem and the example are:
My dataset is composed by RGB pictures (CelebA dataset) while the one from the example is black and white (MNIST)
The dimensions of my pictures are 64x64 while MNIST pictures are 28x28
That said here is my code:
#include <torch/torch.h>
#include <cmath>
#include <cstdio>
#include <iostream>
#include "CustomDataset.h"
#include "parameters.h"
// The size of the noise vector fed to the generator.
const int64_t kNoiseSize = 100;
// The batch size for training.
const int64_t kBatchSize = 64;
// The number of epochs to train.
const int64_t kNumberOfEpochs = 30;
// Where to find the MNIST dataset.
const char* kDataFolder = "./data";
// After how many batches to create a new checkpoint periodically.
const int64_t kCheckpointEvery = 20;
// How many images to sample at every checkpoint.
const int64_t kNumberOfSamplesPerCheckpoint = 10;
// After how many batches to log a new update with the loss value.
const int64_t kLogInterval = 10;
using namespace torch;
struct DCGANGeneratorImpl : nn::Module {
DCGANGeneratorImpl(int kNoiseSize)
: conv1(nn::ConvTranspose2dOptions(kNoiseSize, 256, 4)
.bias(false)),
batch_norm1(256),
conv2(nn::ConvTranspose2dOptions(256, 128, 4)
.stride(2)
.padding(1)
.bias(false)),
batch_norm2(128),
conv3(nn::ConvTranspose2dOptions(128, 64, 4)
.stride(2)
.padding(1)
.bias(false)),
batch_norm3(64),
conv4(nn::ConvTranspose2dOptions(64, 32, 4)
.stride(2)
.padding(1)
.bias(false)),
batch_norm4(32),
conv5(nn::ConvTranspose2dOptions(32, 3, 4)
.stride(2)
.padding(1)
.bias(false))
{
register_module("conv1", conv1);
register_module("conv2", conv2);
register_module("conv3", conv3);
register_module("conv4", conv4);
register_module("conv5", conv5);
register_module("batch_norm1", batch_norm1);
register_module("batch_norm2", batch_norm2);
register_module("batch_norm3", batch_norm3);
register_module("batch_norm4", batch_norm4);
}
torch::Tensor forward(torch::Tensor x)
{
x = torch::relu(batch_norm1(conv1(x)));
x = torch::relu(batch_norm2(conv2(x)));
x = torch::relu(batch_norm3(conv3(x)));
x = torch::relu(batch_norm4(conv4(x)));
x = torch::tanh(conv5(x));
return x;
}
nn::ConvTranspose2d conv1, conv2, conv3, conv4, conv5;
nn::BatchNorm2d batch_norm1, batch_norm2, batch_norm3, batch_norm4;
};
TORCH_MODULE(DCGANGenerator);
int main(int argc, const char* argv[]) {
torch::manual_seed(1);
// Create the device we pass around based on whether CUDA is available.
torch::Device device(torch::kCPU);
if (torch::cuda::is_available()) {
std::cout << "CUDA is available! Training on GPU." << std::endl;
device = torch::Device(torch::kCUDA);
}
DCGANGenerator generator(kNoiseSize);
generator->to(device);
nn::Sequential discriminator(
// Layer 1
nn::Conv2d(
nn::Conv2dOptions(3, 64, 4).stride(2).padding(1).bias(false)),
nn::LeakyReLU(nn::LeakyReLUOptions().negative_slope(0.2)),
//output is 32x32
// Layer 2
nn::Conv2d(
nn::Conv2dOptions(64, 128, 4).stride(2).padding(1).bias(false)),
nn::BatchNorm2d(128),
nn::LeakyReLU(nn::LeakyReLUOptions().negative_slope(0.2)),
//output is 16x16
// Layer 3
nn::Conv2d(
nn::Conv2dOptions(128, 64, 4).stride(2).padding(1).bias(false)),
nn::BatchNorm2d(64),
nn::LeakyReLU(nn::LeakyReLUOptions().negative_slope(0.2)),
//output is 8x8
// Layer 4
nn::Conv2d(
nn::Conv2dOptions(64, 32, 5).stride(1).padding(0).bias(false)),
nn::LeakyReLU(nn::LeakyReLUOptions().negative_slope(0.2)),
// output is 4x4
// Layer 5
nn::Conv2d(
nn::Conv2dOptions(32, 1, 4).stride(1).padding(0).bias(false)),
nn::Sigmoid());
discriminator->to(device);
// Where all my pictures are;
std::string file_location{"dataset/img_align_celeba/*.jpg"};
auto dataset = CustomDataset(file_location).map(data::transforms::Stack<>());
const int64_t batches_per_epoch =
std::ceil(dataset.size().value() / static_cast<double>(kBatchSize));
auto data_loader = torch::data::make_data_loader(
std::move(dataset),
torch::data::DataLoaderOptions().batch_size(kBatchSize).workers(2));
torch::optim::Adam generator_optimizer(
generator->parameters(), torch::optim::AdamOptions(2e-4).beta1(0.5));
torch::optim::Adam discriminator_optimizer(
discriminator->parameters(), torch::optim::AdamOptions(2e-4).beta1(0.5));
int64_t checkpoint_counter = 1;
for (int64_t epoch = 1; epoch <= kNumberOfEpochs; ++epoch) {
int64_t batch_index = 0;
for (torch::data::Example<>& batch : *data_loader) {
// Train discriminator with real images.
discriminator->zero_grad();
torch::Tensor real_images = batch.data.to(device);
torch::Tensor real_labels =
torch::empty(batch.data.size(0), device).uniform_(0.8, 1.0);
torch::Tensor real_output = discriminator->forward(real_images);
torch::Tensor d_loss_real =
torch::binary_cross_entropy(real_output, real_labels);
d_loss_real.backward();
// Train discriminator with fake images.
torch::Tensor noise =
torch::randn({batch.data.size(0), kNoiseSize, 1, 1}, device);
torch::Tensor fake_images = generator->forward(noise);
torch::Tensor fake_labels = torch::zeros(batch.data.size(0), device);
torch::Tensor fake_output = discriminator->forward(fake_images.detach());
torch::Tensor d_loss_fake =
torch::binary_cross_entropy(fake_output, fake_labels);
d_loss_fake.backward();
torch::Tensor d_loss = d_loss_real + d_loss_fake;
discriminator_optimizer.step();
// Train generator.
generator->zero_grad();
fake_labels.fill_(1);
fake_output = discriminator->forward(fake_images);
torch::Tensor g_loss =
torch::binary_cross_entropy(fake_output, fake_labels);
g_loss.backward();
generator_optimizer.step();
batch_index++;
if (batch_index % kCheckpointEvery == 0) {
// Checkpoint the model and optimizer state.
torch::save(generator, "generator-checkpoint.pt");
torch::save(generator_optimizer, "generator-optimizer-checkpoint.pt");
torch::save(discriminator, "discriminator-checkpoint.pt");
torch::save(
discriminator_optimizer, "discriminator-optimizer-checkpoint.pt");
// Sample the generator and save the images.
torch::Tensor samples = generator->forward(torch::randn(
{kNumberOfSamplesPerCheckpoint, kNoiseSize, 1, 1}, device));
torch::save(
samples,
torch::str("dcgan-sample-", checkpoint_counter, ".pt"));
std::cout << "\n-> checkpoint " << ++checkpoint_counter << '\n';
}
}
}
std::cout << "Training complete!" << std::endl;
}
I save the minibatches from time to time and plot the result of inputing noise over the Generator. The problem is that in the MNIST example results are correct but in my case for each output picture I see like 9 smaller pictures with faces instead of one (see the picture attached).
How is it possible that the generator is outputting a correct shape but with 9 almost identical faces instead of one?
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;
}
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;
}