Commit 88006c0b authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

* added support for polydata in VtkImageReader

* work on Columbia module: simple mesh visualization
parent d5a2b1f4
......@@ -43,9 +43,11 @@ namespace campvis {
: VisualizationPipeline()
, _camera("camera", "Camera")
, _imageReader()
, _vtkReader()
, _vr(_effectiveRenderTargetSize)
, _sr(_effectiveRenderTargetSize)
, _src(_effectiveRenderTargetSize)
, _gr(_effectiveRenderTargetSize)
, _trackballEH(0)
{
addProperty(&_camera);
......@@ -54,10 +56,12 @@ namespace campvis {
_eventHandlers.push_back(_trackballEH);
addProcessor(&_imageReader);
addProcessor(&_vtkReader);
addProcessor(&_splitter);
addProcessor(&_vr);
addProcessor(&_src);
addProcessor(&_sr);
addProcessor(&_gr);
}
Columbia1::~Columbia1() {
......@@ -71,6 +75,8 @@ namespace campvis {
_camera.addSharedProperty(&_vr.p_camera);
_camera.addSharedProperty(&_src.p_camera);
_camera.addSharedProperty(&_gr.p_camera);
_vr.p_outputImage.setValue("vr");
_sr.p_targetImageID.setValue("sr");
_src.p_targetImageID.setValue("src");
......@@ -81,6 +87,10 @@ namespace campvis {
_imageReader.p_targetImageID.setValue("reader.output");
_imageReader.p_targetImageID.connect(&_splitter.p_inputID);
_vtkReader.p_targetImageID.setValue("mesh");
_vtkReader.p_url.setValue("D:/Medical Data/Columbia/inputs/Myocardium Meshes/FullVolumeLV_3D_25Hz_ED_Mesh_Endo.vtk");
_vtkReader.p_targetImageID.connect(&_gr.p_geometryID);
_splitter.p_outputID.connect(&_vr.p_inputVolume);
_splitter.p_outputID.connect(&_src.p_sourceImageID);
_splitter.p_outputID.connect(&_sr.p_sourceImageID);
......@@ -90,6 +100,8 @@ namespace campvis {
dvrTF->addGeometry(TFGeometry1D::createQuad(tgt::vec2(.4f, .5f), tgt::col4(0, 255, 0, 128), tgt::col4(0, 255, 0, 128)));
static_cast<TransferFunctionProperty*>(_vr.getProperty("transferFunction"))->replaceTF(dvrTF);
_gr.p_renderTargetID.setValue("gr");
_trackballEH->setViewportSize(_effectiveRenderTargetSize.getValue());
_effectiveRenderTargetSize.s_changed.connect<Columbia1>(this, &Columbia1::onRenderTargetSizeChanged);
}
......
......@@ -36,10 +36,12 @@
#include "modules/io/processors/ltfimagereader.h"
#include "modules/io/processors/vtkimagereader.h"
#include "modules/columbia/processors/imageseriessplitter.h"
#include "modules/columbia/processors/strainraycaster.h"
#include "modules/vis/processors/sliceextractor.h"
#include "modules/vis/processors/volumerenderer.h"
#include "modules/vis/processors/geometryrenderer.h"
namespace campvis {
class Columbia1 : public VisualizationPipeline {
......@@ -77,10 +79,12 @@ namespace campvis {
CameraProperty _camera;
LtfImageReader _imageReader;
VtkImageReader _vtkReader;
ImageSeriesSplitter _splitter;
VolumeRenderer _vr;
StrainRaycaster _src;
SliceExtractor _sr;
GeometryRenderer _gr;
TrackballNavigationEventHandler* _trackballEH;
......
......@@ -37,6 +37,7 @@
#include "tgt/filesystem.h"
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/indexedmeshgeometry.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/tools/stringutils.h"
......@@ -80,86 +81,108 @@ namespace campvis {
if (curLine.find("# vtk DataFile Version") != 0)
throw tgt::FileException("Unknown identifier in vtk file.", p_url.getValue());
// init optional parameters with sane default values
bool binary = false;
std::string url;
size_t dimensionality = 3;
tgt::svec3 size(static_cast<size_t>(0));
tgt::vec3 voxelSize(1.f);
tgt::vec3 imageOffset(0.f);
// next line is the header - contains only unimportant data
curLine = getTrimmedLine(file);
// this line is the format
curLine = StringUtils::lowercase(getTrimmedLine(file));
if (curLine == "ascii")
binary = false;
else if (curLine == "binary")
binary = true;
else
if (curLine == "binary")
throw tgt::FileException("Binary data format currently unsupported.", p_url.getValue());
else if (curLine != "ascii")
throw tgt::FileException("Unsupported format in vtk file - expected binary or ascii.", p_url.getValue());
// now comes the dataset structure
curLine = StringUtils::lowercase(getTrimmedLine(file));
std::vector<std::string> splitted = StringUtils::split(curLine, " ");
if (splitted.size() != 2 || splitted[0] != "dataset" || splitted[1] != "structured_points")
throw tgt::FileException("Unsupported dataset structure in vtk file - expected \"DATASET STRUCTURED_POINTS\".", p_url.getValue());
// now comes dimensions, spacing and origin:
for (size_t i = 0; i < 3; ++i) {
std::stringstream ss(StringUtils::lowercase(getTrimmedLine(file)));
ss >> curLine;
if (curLine == "dimensions") {
ss >> size.x >> size.y >> size.z;
if (size.z == 1)
dimensionality = 2;
if (size.y == 1)
dimensionality = 1;
}
else if (curLine == "spacing") {
ss >> voxelSize.x >> voxelSize.y >> voxelSize.z;
}
else if (curLine == "origin") {
ss >> imageOffset.x >> imageOffset.y >> imageOffset.z;
}
else {
throw tgt::FileException("Unsupported dataset structure field '" + curLine + "' in vtk file.", p_url.getValue());
}
if (splitted.size() == 2 && splitted[0] == "dataset") {
if (splitted[1] == "structured_points")
parseStructuredPoints(data, file);
else if (splitted[1] == "polydata")
parsePolydata(data, file);
else
throw tgt::FileException("Unsupported dataset structure in vtk file - expected \"DATASET STRUCTURED_POINTS\" or \"DATASET POLYDATA\".", p_url.getValue());
}
else {
throw tgt::FileException("Unexpected tokens in vtk file.", p_url.getValue());
}
// now come the dataset attributes "POINT_DATA ..."
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
if (splitted.size() != 2 || splitted[0] != "point_data")
throw tgt::FileException("Unsupported dataset attribute '" + splitted[0] + "' in vtk file - expected \"POINT_DATA n\".", p_url.getValue());
size_t numPoints = StringUtils::fromString<size_t>(splitted[1]);
}
catch (tgt::Exception& e) {
LERROR("Error while parsing VTK file: " << e.what());
return;
}
catch (std::exception& e) {
LERROR("Error while parsing VTK file: " << e.what());
return;
}
if (numPoints < tgt::hmul(size))
throw tgt::FileException("Number of points in dataset (" + splitted[0] + ") doesn't match dimensions: " + StringUtils::toString(size), p_url.getValue());
validate(INVALID_RESULT);
}
// now comes the data description block "FIELD ..."
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
if (splitted.size() != 3 || splitted[0] != "field")
throw tgt::FileException("Unsupported dataset attribute '" + splitted[0] + "' in vtk file - expected \"FIELD ...\".", p_url.getValue());
size_t numArrays = StringUtils::fromString<size_t>(splitted[2]);
void VtkImageReader::parseStructuredPoints(DataContainer& data, std::ifstream& file) throw (tgt::Exception, std::exception) {
// init optional parameters with sane default values
std::string url;
size_t dimensionality = 3;
tgt::svec3 size(static_cast<size_t>(0));
if (numArrays != 1)
throw tgt::FileException("Multiple arrays in data set currently not supported - too lazy...", p_url.getValue());
tgt::vec3 voxelSize(1.f);
tgt::vec3 imageOffset(0.f);
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
size_t numTuples = StringUtils::fromString<size_t>(splitted[1]);
size_t numComponents = StringUtils::fromString<size_t>(splitted[2]);
std::string curLine;
std::vector<std::string> splitted;
// now comes dimensions, spacing and origin:
for (size_t i = 0; i < 3; ++i) {
std::stringstream ss(StringUtils::lowercase(getTrimmedLine(file)));
ss >> curLine;
if (curLine == "dimensions") {
ss >> size.x >> size.y >> size.z;
if (size.z == 1)
dimensionality = 2;
if (size.y == 1)
dimensionality = 1;
}
else if (curLine == "spacing") {
ss >> voxelSize.x >> voxelSize.y >> voxelSize.z;
}
else if (curLine == "origin") {
ss >> imageOffset.x >> imageOffset.y >> imageOffset.z;
}
else {
throw tgt::FileException("Unsupported dataset structure field '" + curLine + "' in vtk file.", p_url.getValue());
}
}
// now come the dataset attributes "POINT_DATA ..."
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
if (splitted.size() != 2 || splitted[0] != "point_data")
throw tgt::FileException("Unsupported dataset attribute '" + splitted[0] + "' in vtk file - expected \"POINT_DATA n\".", p_url.getValue());
size_t numPoints = StringUtils::fromString<size_t>(splitted[1]);
if (numTuples * numComponents != numPoints)
throw tgt::FileException("Number of points in dataset doesn't match dimensions of data field", p_url.getValue());
if (numPoints < tgt::hmul(size))
throw tgt::FileException("Number of points in dataset (" + splitted[0] + ") doesn't match dimensions: " + StringUtils::toString(size), p_url.getValue());
if (! binary) {
ImageData* image = new ImageData(dimensionality, size, 1);
ImageRepresentationLocal* rep = 0;
// now comes the data description block "FIELD ..."
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
if (splitted.size() != 3 || splitted[0] != "field")
throw tgt::FileException("Unsupported dataset attribute '" + splitted[0] + "' in vtk file - expected \"FIELD ...\".", p_url.getValue());
size_t numArrays = StringUtils::fromString<size_t>(splitted[2]);
if (numArrays != 1)
throw tgt::FileException("Multiple arrays in data set currently not supported - too lazy...", p_url.getValue());
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
size_t numTuples = StringUtils::fromString<size_t>(splitted[1]);
size_t numComponents = StringUtils::fromString<size_t>(splitted[2]);
if (numTuples * numComponents != numPoints)
throw tgt::FileException("Number of points in dataset doesn't match dimensions of data field", p_url.getValue());
ImageData* image = new ImageData(dimensionality, size, 1);
ImageRepresentationLocal* rep = 0;
#define DISPATCH_PARSING(VTK_TYPE, C_TYPE, TMP_TYPE) \
do { \
......@@ -174,37 +197,81 @@ namespace campvis {
} \
} while (0)
DISPATCH_PARSING("unsigned_char" , uint8_t, uint16_t);
DISPATCH_PARSING("char" , int8_t, int16_t);
DISPATCH_PARSING("unsigned_short" , uint16_t, uint16_t);
DISPATCH_PARSING("short" , int16_t, int16_t);
DISPATCH_PARSING("unsigned_int" , uint32_t, uint32_t);
DISPATCH_PARSING("int" , int32_t, int32_t);
DISPATCH_PARSING("float" , float, float);
if (rep != 0) {
// all parsing done - lets create the image:
image->setMappingInformation(ImageMappingInformation(size, imageOffset + p_imageOffset.getValue(), voxelSize + p_voxelSize.getValue()));
data.addData(p_targetImageID.getValue(), image);
p_targetImageID.issueWrite();
DISPATCH_PARSING("unsigned_char" , uint8_t, uint16_t);
DISPATCH_PARSING("char" , int8_t, int16_t);
DISPATCH_PARSING("unsigned_short" , uint16_t, uint16_t);
DISPATCH_PARSING("short" , int16_t, int16_t);
DISPATCH_PARSING("unsigned_int" , uint32_t, uint32_t);
DISPATCH_PARSING("int" , int32_t, int32_t);
DISPATCH_PARSING("float" , float, float);
if (rep != 0) {
// all parsing done - lets create the image:
image->setMappingInformation(ImageMappingInformation(size, imageOffset + p_imageOffset.getValue(), voxelSize + p_voxelSize.getValue()));
data.addData(p_targetImageID.getValue(), image);
p_targetImageID.issueWrite();
}
else {
throw tgt::FileException("Error while parsing the data.", p_url.getValue());
}
}
void VtkImageReader::parsePolydata(DataContainer& data, std::ifstream& file) throw (tgt::Exception, std::exception) {
std::string curLine;
std::vector<std::string> splitted;
std::vector<uint16_t> indices;
std::vector<tgt::vec3> vertices;
std::vector<tgt::vec3> normals;
while (file.good()) {
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
if (splitted.size() == 3 && splitted[0] == "points") {
size_t numVertices = StringUtils::fromString<size_t>(splitted[1]);
vertices.resize(numVertices, tgt::vec3(0.f));
// TODO: make parsing more robust...
for (size_t i = 0; i < numVertices; ++i) {
file >> vertices[i].x >> vertices[i].y >> vertices[i].z;
}
else {
throw tgt::FileException("Error while parsing the data.", p_url.getValue());
}
else if (splitted.size() == 3 && splitted[0] == "polygons") {
size_t numPolygons = StringUtils::fromString<size_t>(splitted[1]);
size_t numIndices = StringUtils::fromString<size_t>(splitted[2]);
indices.resize(numIndices, 0);
size_t i = 0;
// TODO: make parsing more robust...
for (size_t j = 0; j < numPolygons && i < numIndices; ++j) {
int tmp;
file >> tmp >> indices[i++];
file >> indices[i++];
file >> indices[i++];
}
}
else {
throw tgt::FileException("Binary data format currently unsupported.", p_url.getValue());
if (splitted.size() == 2 && splitted[0] == "point_data") {
size_t numPoints = StringUtils::fromString<size_t>(splitted[1]);
curLine = StringUtils::lowercase(getTrimmedLine(file));
splitted = StringUtils::split(curLine, " ");
if (splitted.size() == 3 && splitted[0] == "normals") {
normals.resize(numPoints, tgt::vec3(0.f));
// TODO: make parsing more robust...
for (size_t i = 0; i < numPoints; ++i) {
file >> normals[i].x >> normals[i].y >> normals[i].z;
}
}
}
}
catch (tgt::Exception& e) {
LERROR("Error while parsing VTK file: " << e.what());
return;
}
catch (std::exception& e) {
LERROR("Error while parsing VTK file: " << e.what());
return;
}
validate(INVALID_RESULT);
// all parsing done - lets create the image:
IndexedMeshGeometry* g = new IndexedMeshGeometry(indices, vertices, std::vector<tgt::vec3>(), std::vector<tgt::vec4>(), normals);
data.addData(p_targetImageID.getValue(), g);
p_targetImageID.issueWrite();
}
}
\ No newline at end of file
......@@ -32,6 +32,7 @@
#include <string>
#include "tgt/exception.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/properties/datanameproperty.h"
#include "core/properties/numericproperty.h"
......@@ -73,6 +74,9 @@ namespace campvis {
Vec3Property p_voxelSize; ///< Voxel Size in mm
protected:
void parseStructuredPoints(DataContainer& data, std::ifstream& file) throw (tgt::Exception, std::exception);
void parsePolydata(DataContainer& data, std::ifstream& file) throw (tgt::Exception, std::exception);
static const std::string loggerCat_;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment