Commit dfd14931 authored by Emmanuel Promayon's avatar Emmanuel Promayon
Browse files

Merge branch 'bug/#162' into develop

parents 41fb14e1 126b6f4f
......@@ -31,25 +31,33 @@
#include <QTextStream>
#include <Application.h>
#include <QFileDialog>
#include <VtkMeshComponent.h>
#include <MeshComponent.h>
#include <QPushButton>
#include <QLayout>
// CamiTK includes
#include <ActionWidget.h>
// Vtk includes
#include <vtkGeometryFilter.h>
#include <vtkTriangleFilter.h>
#include <vtkCleanPolyData.h>
#include <vtkPointData.h>
#include <vtkPolyDataNormals.h>
#include <vtkCell.h>
using namespace camitk;
// --------------- Constructor -------------------
ExportAsMDL::ExportAsMDL(ActionExtension* extension) : Action(extension) {
ExportAsMDL::ExportAsMDL ( ActionExtension* extension ) : Action ( extension ) {
// Setting name, description and input component
setName("ExportAsMDL");
setDescription(tr("Export As MDL"));
setComponent("VtkMeshComponent");
setName ( "Export As MDL" );
setDescription ( tr ( "Export As MDL (an old legacy file format from early CAMI devices). This is kept for historical reason only." ) );
setComponent ( "MeshComponent" );
// Setting classification family and tags
setFamily("Mesh Processing");
setFamily ( "Mesh Processing" );
// DO NOT Put any GUI instanciation here,
// If you need, do it in getWidget() method, using lazy instanciation
......@@ -62,79 +70,176 @@ ExportAsMDL::~ExportAsMDL() {
// (except if you use smart pointers of course !!)
}
// --------------- getWidget -------------------
QWidget* ExportAsMDL::getWidget() {
// Use lazy instanciation (instanciate only once and when needed)
// We will return the default action widget with an additionnal button
// build or update the widget
if ( !actionWidget ) {
// Setting the widget containing the parameters, using the default widget
actionWidget = new ActionWidget ( this );
QPushButton* outputbutton = new QPushButton ( "Output file" );
outputfile = new QLineEdit();
actionWidget->layout()->addWidget ( outputbutton );
actionWidget->layout()->addWidget ( outputfile );
QObject::connect ( outputbutton, SIGNAL ( released() ), SLOT ( outputMDL() ) );
QObject::connect ( outputfile, SIGNAL ( textChanged ( const QString& ) ), this, SLOT ( outputFileChanged ( const QString& ) ) );
}
else {
// make sure the widget has updated targets
dynamic_cast<ActionWidget*> ( actionWidget )->updateTargets();
}
return actionWidget;
}
// --------------- outputMDL -------------------
void ExportAsMDL::outputMDL() {
QString ofile = QFileDialog::getSaveFileName(NULL, tr("Save As MDL..."), QString(), tr("MDL format(*.mdl)"));
QString ofile = QFileDialog::getSaveFileName ( NULL, tr ( "Save As MDL..." ), QString(), tr ( "MDL format(*.mdl)" ) );
if (!ofile.isEmpty()) {
outputfile->setText(ofile);
if ( !ofile.isEmpty() ) {
outputfile->setText ( ofile );
}
}
void ExportAsMDL::outputFileChanged(const QString& ofile) {
cout << "output file" << ofile.toStdString() << endl;
fn = ofile;
// --------------- outputFileChanged -------------------
void ExportAsMDL::outputFileChanged ( const QString& ofile ) {
filename = ofile;
}
// --------------- apply -------------------
Action::ApplyStatus ExportAsMDL::apply() {
foreach (Component * comp, getTargets()) {
VtkMeshComponent* input = dynamic_cast<VtkMeshComponent*> (comp);
process(input);
Action::ApplyStatus returnStatus = SUCCESS;
foreach ( Component* comp, getTargets() ) {
MeshComponent* input = dynamic_cast<MeshComponent*> ( comp );
if ( input ) {
process ( input );
}
else {
CAMITK_ERROR ( "ExportAsMDL", "apply", "Target component \"" << comp->getName().toUtf8().constData() << "\" is of type \"" << comp->getHierarchy().value(0).toStdString() << "\", expecting MeshComponent" );
returnStatus = ERROR; // Bad input (should not be possible)
}
}
return SUCCESS;
return returnStatus;
}
// --------------- process -------------------
void ExportAsMDL::process(MeshComponent* comp) {
cout << "Action ExportAsMDL called on " << comp->getName().toStdString() << endl;
if (!fn.isEmpty()) {
VtkMeshComponent* input = dynamic_cast<VtkMeshComponent*> (comp);
if (input) {
// if the filename does not have the ".mdl" extension, add it
QString extension = fn.right(4);
QString txt(".mdl");
if (extension.compare(txt) != 0) {
// add the extension to the filename
fn += txt;
}
input->exportMDL(fn.toStdString());
}
void ExportAsMDL::process ( MeshComponent* comp ) {
if ( !filename.isEmpty() ) {
// if the filename does not have the ".mdl" extension, add it
QFileInfo fileinfo(filename);
if (fileinfo.suffix() != ".mdl")
filename += ".mdl";
saveMeshComponentToMDL ( comp );
}
else {
cout << "Provide an output file name. " << endl;
CAMITK_WARNING ( "ExportAsMDL", "process", "Output file is missing, please provide one. " );
}
}
// --------------- getWidget -------------------
QWidget* ExportAsMDL::getWidget() {
// Use lazy instanciation (instanciate only once and when needed)
// We will return the default action widget with an additionnal button
// --------------- saveMeshComponentToMDL -------------------
void ExportAsMDL::saveMeshComponentToMDL( MeshComponent* comp ) {
// build or update the widget
if ( !actionWidget ) {
// Setting the widget containing the parameters, using the default widget
actionWidget = new ActionWidget ( this );
int i;
// MDL format supports only triangles. Hence, this dataset triangularized before
// being exported (this operation is then NOT reversible).
// if the dataset is a volumetric mesh (e.g. hexahedrons), only the external surface is exported.
QPushButton* outputbutton = new QPushButton("Output file");
outputfile = new QLineEdit();
//extract external surface
vtkSmartPointer<vtkGeometryFilter> geomF = vtkSmartPointer<vtkGeometryFilter>::New();
geomF->SetInputData ( comp->getPointSet() );
// triangles
vtkSmartPointer<vtkTriangleFilter> triangleF = vtkSmartPointer<vtkTriangleFilter>::New();
triangleF->SetInputData ( geomF->GetOutput() );
// clean unused
vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
cleaner->SetInputData ( triangleF->GetOutput() );
cleaner->Update();
vtkSmartPointer<vtkPolyData> ds = cleaner->GetOutput();
//--- write as .mdl file (Registration format)
std::ofstream o ( filename.toUtf8().constData() );
//--- name
o << "[Name, STRING]" << std::endl;
o << comp->getName().toStdString() << std::endl;
o << std::endl;
double pt[3];
actionWidget->layout()->addWidget(outputbutton);
actionWidget->layout()->addWidget(outputfile);
//--- vertices
o << "[Vertices, ARRAY1<POINT3D>]" << std::endl;
if (ds->GetPoints() != nullptr) {
o << ds->GetPoints()->GetNumberOfPoints() << std::endl;
QObject::connect(outputbutton, SIGNAL(released()), SLOT(outputMDL()));
QObject::connect(outputfile, SIGNAL(textChanged(const QString&)), this, SLOT(outputFileChanged(const QString&)));
for ( i = 0; i < ds->GetPoints()->GetNumberOfPoints(); i++ ) {
ds->GetPoints()->GetPoint ( i, pt );
o << pt[0] << " " << pt[1] << " " << pt[2] << std::endl;
}
}
o << std::endl;
//--- normals
o << "[Normals, ARRAY1<VECTOR3D>]" << std::endl;
if ( ds->GetPointData() && ds->GetPointData()->GetNormals() ) {
// save existing normals
o << ds->GetPointData()->GetNormals()->GetNumberOfTuples() << std::endl;
for ( i = 0; i < ds->GetPointData()->GetNormals()->GetNumberOfTuples(); i++ ) {
ds->GetPointData()->GetNormals()->GetTuple ( i, pt );
o << pt[0] << " " << pt[1] << " " << pt[2] << std::endl;
}
}
else {
// make sure the widget has updated targets
dynamic_cast<ActionWidget*> ( actionWidget )->updateTargets();
// compute the normals
vtkSmartPointer<vtkPolyDataNormals> pNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
pNormals->SetInputData ( ds );
pNormals->Update();
if (pNormals->GetOutput()->GetPointData() != nullptr && pNormals->GetOutput()->GetPointData()->GetNormals() != nullptr) {
o << pNormals->GetOutput()->GetPointData()->GetNormals()->GetNumberOfTuples() << std::endl;
for ( i = 0; i < pNormals->GetOutput()->GetPointData()->GetNormals()->GetNumberOfTuples(); i++ ) {
pNormals->GetOutput()->GetPointData()->GetNormals()->GetTuple ( i, pt );
o << pt[0] << " " << pt[1] << " " << pt[2] << std::endl;
}
}
}
return actionWidget;
}
o << std::endl;
//--- triangles
int j;
o << "[Triangles, ARRAY1<STRING>]" << std::endl;
o << ds->GetNumberOfCells() << std::endl;
for ( i = 0; i < ds->GetNumberOfCells(); i++ ) {
// write it twice
for ( j = 0; j < ds->GetCell ( i )->GetNumberOfPoints(); j++ ) {
o << ds->GetCell ( i )->GetPointId ( j ) << " ";
}
for ( j = 0; j < ds->GetCell ( i )->GetNumberOfPoints(); j++ ) {
o << ds->GetCell ( i )->GetPointId ( j ) << " ";
}
o << std::endl;
}
}
......@@ -60,13 +60,16 @@ public slots:
private:
/// helper method to simplify the target component processing
virtual void process(camitk::MeshComponent*);
void process ( camitk::MeshComponent* );
/// output file
QString fn;
QString filename;
/// output file editor
QLineEdit* outputfile;
/// export MeshComponent in MDL format
void saveMeshComponentToMDL( camitk::MeshComponent* );
};
......
......@@ -37,7 +37,7 @@ using namespace camitk;
// -------------------- ExtractSurface --------------------
ExtractSurface::ExtractSurface(ActionExtension* extension) : Action(extension) {
this->setName("ExtractSurface");
this->setName("Extract Surface");
this->setDescription(tr("Extract Surface from Volumetric Mesh"));
this->setComponent("MeshComponent");
this->setFamily("Mesh Processing");
......
......@@ -46,8 +46,8 @@ using namespace camitk;
// --------------- Constructor -------------------
LoadTextureFromBMP::LoadTextureFromBMP(ActionExtension* extension) : Action(extension) {
// Setting name, description and input component
setName("LoadTextureFromBMP");
setDescription(tr("LoadTextureFromBMP"));
setName("Load Texture From BMP");
setDescription(tr("Load Texture From BMP"));
setComponent("MeshComponent");
// Setting classification family and tags
......@@ -63,9 +63,9 @@ LoadTextureFromBMP::~LoadTextureFromBMP() {
// Delete stuff if you create stuff
// (except if you use smart pointers of course !!)
}
void LoadTextureFromBMP::loadBMP() {
cout << "Action LoadTextureFromBMP called on " << endl;
// --------------- loadBMP -------------------
void LoadTextureFromBMP::loadBMP() {
trFile = QFileDialog::getOpenFileName(NULL, tr("Open BMP File"), QString(), "BMP File (*.bmp)");
}
......@@ -83,8 +83,6 @@ Action::ApplyStatus LoadTextureFromBMP::apply() {
// --------------- process -------------------
void LoadTextureFromBMP::process(MeshComponent* comp) {
cout << "Action LoadTextureFromBMP called on " << comp->getName().toStdString() << endl;
if (!trFile.isEmpty()) {
vtkSmartPointer<vtkBMPReader> bmpReader = vtkSmartPointer<vtkBMPReader>::New();
bmpReader->SetFileName(trFile.toStdString().c_str());
......@@ -100,7 +98,7 @@ void LoadTextureFromBMP::process(MeshComponent* comp) {
comp->setTexture(texture);
}
else {
cout << "Texture file is missing, please provide a .bmp file. " << endl;
CAMITK_WARNING("LoadTextureFromBMP", "process", "Texture file is missing, please provide a .bmp file. ");
}
}
......
......@@ -50,8 +50,8 @@ using namespace camitk;
// --------------- Constructor -------------------
LoadTransformation::LoadTransformation(ActionExtension* extension) : Action(extension) {
// Setting name, description and input component
setName("LoadTransformation");
setDescription(tr("LoadTransformation"));
setName("Load Transformation");
setDescription(tr("Load Transformation"));
setComponent("MeshComponent");
// Setting classification family and tags
......@@ -80,22 +80,12 @@ Action::ApplyStatus LoadTransformation::apply() {
foreach (Component * comp, getTargets()) {
MeshComponent* input = dynamic_cast<MeshComponent*> ( comp );
process(input);
loadTransformationFile();
}
return SUCCESS;
}
// --------------- apply -------------------
void LoadTransformation::process(MeshComponent* comp) {
cout << "Action LoadTransformation called on " << comp->getName().toStdString() << endl;
loadTransformationFile();
}
// --------------- loadTransformationFile -------------------
void LoadTransformation::loadTransformationFile() {
......@@ -143,7 +133,7 @@ void LoadTransformation::loadTransformationFile() {
}
}
else {
cout << "Provide a transformation file" << endl;
CAMITK_WARNING("LoadTransformation", "loadTransformationFile", "Transformation file is missing, please provide one. ");
}
}
......
......@@ -55,9 +55,6 @@ public slots:
void openTransformation();
private:
/// helper method to simplify the target component processing
virtual void process(camitk::MeshComponent*);
/// apply transformation
void loadTransformationFile();
......
......@@ -14,4 +14,4 @@ camitk_extension( COMPONENT_EXTENSION
)
# Recursively update the shiboken path variable containing the CamiTK SDK tree structure
set(SHIBOKEN_CAMITK_SDK_PATH ${SHIBOKEN_CAMITK_SDK_PATH}:${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
\ No newline at end of file
set(SHIBOKEN_CAMITK_SDK_PATH ${SHIBOKEN_CAMITK_SDK_PATH}:${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
......@@ -26,26 +26,15 @@
#include "VtkMeshComponent.h"
// -- CamiTK stuff
#include <Application.h>
#include <MeshComponent.h>
#include <Geometry.h>
#include <InteractiveViewer.h>
#include <Property.h>
// -- vtk stuff
#include <vtkPolyData.h>
#include <vtkCleanPolyData.h>
#include <vtkPointData.h>
#include <vtkCell.h>
#include <vtkTriangleFilter.h>
#include <vtkGeometryFilter.h>
#include <vtkPolyDataNormals.h>
#include <vtkDoubleArray.h>
#include <vtkCellData.h>
#include <vtkProperty.h>
using namespace camitk;
// -------------------- default constructor --------------------
VtkMeshComponent::VtkMeshComponent (const QString& fileName) throw(AbortException) : MeshComponent ( fileName ) {
......@@ -58,8 +47,6 @@ VtkMeshComponent::VtkMeshComponent (const QString& fileName) throw(AbortExcepti
setName(VtkMeshUtil::getVtkPointSetHeaderString(myFileName.toStdString()).c_str());
myProperties = NULL;
initialPointData = NULL;
demoPointData = NULL;
// build the vtk data structure from the file
vtkSmartPointer<vtkPointSet> data = VtkMeshUtil::buildVtkPointSet(myFileName.toStdString().c_str(), whatIsIt);
......@@ -73,183 +60,23 @@ VtkMeshComponent::VtkMeshComponent (const QString& fileName) throw(AbortExcepti
// -------------------- destructor --------------------
VtkMeshComponent::~VtkMeshComponent() {
setPointData ( NULL );
InteractiveViewer::get3DViewer()->setColorScale ( false );
// no active data by default
setActiveData(MeshDataModel::POINTS,NULL);
}
// -------------------- initPointData --------------------
void VtkMeshComponent::initPointData() {
// create a new vtkDataArray to store the demo value
demoPointData = vtkSmartPointer<vtkDoubleArray>::New();
int numberOfPoints = getPointSet()->GetNumberOfPoints();
demoPointData->SetNumberOfValues ( numberOfPoints );
demoPointData->SetName ( "the point data" );
for ( vtkIdType i = 0; i < numberOfPoints; ++i ) {
demoPointData->SetValue ( i, 0.0 );
}
// backup the read point data
initialPointData = vtkSmartPointer<vtkPointData>::New();
initialPointData->ShallowCopy(myGeometry->getPointSet()->GetPointData());
// remove the point data
setPointData(NULL);
}
// -------------------- pointPicked --------------------
void VtkMeshComponent::pointPicked ( vtkIdType pointId, bool sel/* picking does not change the selection state, do not bother with the 2nd parameter*/ ) {
MeshComponent::pointPicked(pointId, sel);
// picking show demo point data
demoPointData->SetValue ( pointId, 1.0 - double ( pointId ) / double ( getPointSet()->GetNumberOfPoints() ) );
demoPointData->Modified(); // force an update on the vtk pipeline
refresh(); // refresh display
}
// -------------------- cellPicked --------------------
void VtkMeshComponent::cellPicked ( vtkIdType cellId, bool sel /* picking does not change the selection state, do not bother with the 2nd parameter*/ ) {
MeshComponent::cellPicked(cellId, sel);
// change data for all cell points
vtkSmartPointer<vtkCell> c = getPointSet()->GetCell ( cellId );
for ( vtkIdType i = 0; i < c->GetNumberOfPoints(); i++ ) {
vtkIdType pointId = c->GetPointId ( i );
demoPointData->SetValue ( pointId, 1.0 - double ( pointId ) / double ( getPointSet()->GetNumberOfPoints() ) );
//-- add loaded data arrays
for(vtkIdType i = 0; i < myGeometry->getPointSet()->GetPointData()->GetNumberOfArrays(); i++) {
addPointData(myGeometry->getPointSet()->GetPointData()->GetArrayName(i) , myGeometry->getPointSet()->GetPointData()->GetArray(i));
}
demoPointData->Modified(); // force an update on the vtk pipeline
refresh(); // refresh display
}
// -------------------- showPointData --------------------
void VtkMeshComponent::showPointData(VTK_COMPONENT_POINT_DATA_TYPE type) {
switch (type) {
case NONE:
setPointData ( NULL );
InteractiveViewer::get3DViewer()->setColorScale ( false );
break;
case DEMO:
setPointData ( demoPointData );
InteractiveViewer::get3DViewer()->setColorScaleMinMax ( 0.0, getPointSet()->GetNumberOfPoints() );
InteractiveViewer::get3DViewer()->setColorScaleTitle("Demo Point Data");
InteractiveViewer::get3DViewer()->setColorScale ( true );
break;
case INITIAL:
myGeometry->getPointSet()->GetPointData()->ShallowCopy(initialPointData);
if (initialPointData->GetNumberOfArrays() > 0) {
double range[2];
myGeometry->getPointSet()->GetPointData()->GetScalars()->GetRange ( range );
InteractiveViewer::get3DViewer()->setColorScaleMinMax ( range[0], range[1] );
InteractiveViewer::get3DViewer()->setColorScaleTitle("VTK Point Data");
InteractiveViewer::get3DViewer()->setColorScale ( true );
}
else {
InteractiveViewer::get3DViewer()->setColorScale ( false );
}
break;
for(vtkIdType i = 0; i < myGeometry->getPointSet()->GetCellData()->GetNumberOfArrays(); i++) {
addCellData(myGeometry->getPointSet()->GetCellData()->GetArrayName(i) , myGeometry->getPointSet()->GetCellData()->GetArray(i));
}
refresh();
}
// -------------------- exportMDL --------------------
bool VtkMeshComponent::exportMDL ( std::string filename ) {
if ( myGeometry ) {
int i;
// MDL format supports only triangles. Hence, this dataset triangularized before
// being exported (this operation is then NOT reversible).
// if the dataset is a volumetric mesh (e.g. hexahedrons), only the external surface is exported.
//extract external surface
vtkSmartPointer<vtkGeometryFilter> geomF = vtkSmartPointer<vtkGeometryFilter>::New();
geomF->SetInputData(getPointSet());
// triangles
vtkSmartPointer<vtkTriangleFilter> triangleF = vtkSmartPointer<vtkTriangleFilter>::New();
triangleF->SetInputData(geomF->GetOutput());
// clean unused
vtkSmartPointer<vtkCleanPolyData> cleaner = vtkSmartPointer<vtkCleanPolyData>::New();
cleaner->SetInputData(triangleF->GetOutput());
cleaner->Update();
vtkSmartPointer<vtkPolyData> ds = cleaner->GetOutput();
//--- write as .mdl file (Registration format)
std::ofstream o ( filename.c_str() );
//--- name
o << "[Name, STRING]" << std::endl;
o << getName().toStdString() << std::endl;
o << std::endl;
//--- vertices
o << "[Vertices, ARRAY1<POINT3D>]" << std::endl;
o << ds->GetPoints()->GetNumberOfPoints() << std::endl;
double pt[3];
for ( i = 0; i < ds->GetPoints()->GetNumberOfPoints(); i++ ) {
ds->GetPoints()->GetPoint ( i, pt );
o << pt[0] << " " << pt[1] << " " << pt[2] << std::endl;
}
o << std::endl;
//--- normals
o << "[Normals, ARRAY1<VECTOR3D>]" << std::endl;
if ( ds->GetPointData() && ds->GetPointData()->GetNormals() ) {
// save existing normals
o << ds->GetPointData()->GetNormals()->GetNumberOfTuples() << std::endl;
for ( i = 0; i < ds->GetPointData()->GetNormals()->GetNumberOfTuples(); i++ ) {
ds->GetPointData()->GetNormals()->GetTuple ( i, pt );
o << pt[0] << " " << pt[1] << " " << pt[2] << std::endl;
}
}
else {
// compute the normals
vtkSmartPointer<vtkPolyDataNormals> pNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
pNormals->SetInputData( ds );
pNormals->Update();
o << pNormals->GetOutput()->GetPointData()->GetNormals()->GetNumberOfTuples() << std::endl;