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

NEW first complete rewrite of MeshComponent data management

see TODO for list of things to finish.
This first test compiles but is not complete. The
complete rewrite allows for a clear/real separation of data and GUI
(as it should be)
parent 64e826a5
......@@ -72,13 +72,13 @@ void Arrows::update() {
monitorDataArray->SetTuple(pmlComp->getPointId(a), value);
}
pmlComp->addDataArray(camitk::MeshDataModel::POINTS, QString(monitor->getTypeName().c_str()), monitorDataArray);
pmlComp->addDataArray(camitk::MeshComponent::POINTS, QString(monitor->getTypeName().c_str()), monitorDataArray);
}
// ---------------------- hide ----------------------------
void Arrows::hide() {
// remove the current colors
manager->getPMLComponent()->setActiveData(camitk::MeshDataModel::POINTS, NULL);
manager->getPMLComponent()->setDataRepresentationOff();
}
......
......@@ -64,13 +64,13 @@ void Colors::update() {
monitorDataArray->SetValue(pmlComp->getPointId(a), monitor->getValue(i));
}
pmlComp->addDataArray(camitk::MeshDataModel::POINTS, QString(monitor->getTypeName().c_str()), monitorDataArray);
pmlComp->addDataArray(camitk::MeshComponent::POINTS, QString(monitor->getTypeName().c_str()), monitorDataArray);
}
// ---------------------- hide ----------------------------
void Colors::hide() {
// remove the current colors
manager->getPMLComponent()->setActiveData(camitk::MeshDataModel::POINTS, NULL);
manager->getPMLComponent()->setActiveData(camitk::MeshComponent::POINTS, nullptr);
}
......@@ -61,7 +61,7 @@ VtkMeshComponent::VtkMeshComponent (const QString& fileName) throw(AbortExcepti
// -------------------- destructor --------------------
VtkMeshComponent::~VtkMeshComponent() {
// no active data by default
setActiveData(MeshDataModel::POINTS,NULL);
setDataRepresentationOff();
}
// -------------------- initPointData --------------------
......@@ -75,8 +75,7 @@ void VtkMeshComponent::initPointData() {
}
//-- no active data by default
setActiveData(MeshDataModel::POINTS,NULL);
setActiveData(MeshDataModel::CELLS,NULL);
setDataRepresentationOff();
}
//------------------------ getPixmap ---------------------
......
......@@ -28,7 +28,6 @@
#include "Component.h"
#include "Geometry.h"
#include "MeshDataModel.h"
#include "MeshDataView.h"
#include "MeshSelectionModel.h"
#include "MeshSelectionView.h"
......@@ -42,6 +41,8 @@ class QComboBox;
namespace camitk {
class MeshDataModel;
/**
* @ingroup group_sdk_libraries_core_component_mesh
*
......@@ -52,6 +53,31 @@ class CAMITK_API MeshComponent : public Component {
Q_OBJECT
public:
/// @enum DataType Data fields can have different dimensions
enum DataType {
SCALARS = 1, ///< 1D (scalar value)
VECTORS = 2, ///< 3D (3D vector)
TENSORS = 4, ///< 9D (3x3 matrix)
OTHERS = 8 ///< other dimensions (warning: nothing special are managed by this class, no specific interaction)
};
/// @enum FieldType Data fields can be applied to one of this
enum FieldType {
POINTS = 1, ///< data are attached to point
CELLS = 2, ///< data are attached to cells
MESH = 4 ///< data are attached to the whole mesh (generic field data of Vtk)
};
/// @enum RepresentationOf3DData 3D data can be represented by 1 value in different ways
enum RepresentationOf3DData {
HEDGE_HOG, ///< 3D data are represented as 3D vector (show lines starting from the point or center of the cell)
NORM, ///< 3D data are represented in 1D using the norm of the three components
FIRST_COMPONENT, ///< Use only the value of the first component
SECOND_COMPONENT, ///< Use only the value of the second component
THIRD_COMPONENT ///< Use only the value of the third component
//@TODO COLOR, ///< 3D data are represented as a specific color @TODO need to build a specific color map LUT containing as many colors as there is point/cell
};
/** Creates a top-level MeshComponent from a file.
* \note this is only to be used from a Component Extension open(...) or from an Action that creates data from a filter or transformation of a vtkPointSet.
*
......@@ -224,45 +250,53 @@ public:
* @{
*/
/// Get the total number of point and cell data arrays (not taking intou account the field arrays), returns -1 if there is none
int getNumberOfDataArray();
/** @brief Get the number of data arrays of a given type without taking the specific representation into account.
*
* This method does not take into account:
* - the field arrays
* - the specific representation of 3D data (i.e., representation of 3D data as norm or component#i values)
*
* @param fieldFlag is a FieldType or a combinaison of field types.
* @returns the number of arrays corresponding to the field flag
*/
int getNumberOfDataArray(int fieldFlag = POINTS | CELLS);
/**
* @brief Get the data array of specified field type and name.
*
* @param fieldType field type (@see MeshDataModel::FieldType)
* @param fieldType field type
* @param arrayName array name
*
* @return data array
*/
vtkSmartPointer<vtkDataArray> getDataArray(MeshDataModel::FieldType fieldType, const QString& arrayName);
vtkSmartPointer<vtkDataArray> getDataArray(FieldType fieldType, const QString& arrayName);
/**
* @brief Get the data array of specified field type and index.
*
* @param fieldType field type (@see MeshDataModel::FieldType)
* @param fieldType field type
* @param index index
*
* @return data array
*/
vtkSmartPointer<vtkDataArray> getDataArray(MeshDataModel::FieldType fieldType, int index);
vtkSmartPointer<vtkDataArray> getDataArray(FieldType fieldType, int index);
/**
* @brief Add a data array.
*
* @param fieldType field type (@see MeshDataModel::FieldType)
* @param fieldType field type
* @param name name given to the array to add
* @param data data array
*/
void addDataArray ( MeshDataModel::FieldType fieldType, const QString& name, vtkSmartPointer<vtkDataArray> data );
void addDataArray ( FieldType fieldType, const QString& name, vtkSmartPointer<vtkDataArray> data );
/**
* @brief Remove a data array.
*
* @param fieldType field type (@see MeshDataModel::FieldType)
* @param fieldType field type
* @param name name of the array to remove
*/
void removeDataArray ( MeshDataModel::FieldType fieldType, const QString& name );
void removeDataArray ( FieldType fieldType, const QString& name );
/**
* @brief Add a data array linked to the points.
......@@ -280,40 +314,75 @@ public:
*/
void addCellData ( const QString& name, vtkSmartPointer<vtkDataArray> data );
/**
* @brief Get the prop associed to the data.
*
* If the prop does not exist, create it with visibility off.
*
* @param fieldType field type (@see MeshDataModel::FieldType)
* @param name data array name
*
* @return prop
*/
vtkSmartPointer<vtkProp> getDataProp ( MeshDataModel::FieldType fieldType, const QString& name );
///@cond
/// TODO CAMITK_DEPRECATED. This section list all the methods marked as deprecated. They are to be removed in CamiTK 4.1
/// This method was only available in CamiTK 3.4.0 and 4.0.1 to 4.0.4
/// Please use the setDataRepresentationVisibility(fieldType, name, true) method instead.
/** Set the given named scalar data array corresponding to the given field type as the currently active data.
*
* This will set the current active data. If the data has one dimension (scalar),
* it will also show the corresponding values using the
* default color scale and display the color scale in the 3D viewer.
*
* \note if fieldType is POINTS and name is equal to NULL, the color scale is removed from the 3D viewer
* \note if fieldType is POINTS and name is equal to NULL, the color scale is removed from the 3D viewer/
* Please use setDataRepresentationOff() or setDataRepresentationVisibility(fieldType, name, true) instead.
*
* @param fieldType field type (@see MeshDataModel::FieldType)
* @param fieldType field type
* @param name data array name
*
* @see setDataRepresentationOff()
*/
void setActiveData(MeshDataModel::FieldType fieldType, const char* name);
void setActiveData(FieldType fieldType, const char* name);
///@endcond
/// Returns the current value of the display type selected by the user
MeshDataModel::DisplayTypeFor3DData getCurrentDisplayTypePolicy() const;
RepresentationOf3DData getCurrentDisplayTypePolicy() const;
/// Returns the current data view model (model as the M in Qt MVC design pattern)
MeshDataModel* getDataModel();
/// Returns the corresponding vtkFieldData (point data, cell data or field data)
vtkSmartPointer<vtkFieldData> getFieldData(MeshDataModel::FieldType);
vtkSmartPointer<vtkFieldData> getFieldData(FieldType);
/// get the current visibility status of a given data (identified with its name) of a given field type
bool getDataRepresentationVisibility(FieldType, const QString&, RepresentationOf3DData representation = HEDGE_HOG) ;
/// set the visibility of a given representation for a given data (identified with its name) of a given field type (create it if needed)
void setDataRepresentationVisibility(FieldType, const QString&, bool, RepresentationOf3DData representation = HEDGE_HOG);
/// hide all the data representation of a given data type (hide all by default)
void setDataRepresentationOff(int dataType = SCALARS | VECTORS | TENSORS);
/**
* @name Enum management and helper methods
* @{
*/
/// static method that returns the FieldType enum as a QString
static const QMap< int, QString >& getFieldNames();
/// helper method that returns the field type as a string
static const QString getFieldName(const FieldType);
/// static method that returns the DataType enum as a QString
static const QMap< int, QString >& getDataTypeNames();
/// Helper method that returns the datatype as a string
static const QString getDataTypeName(const DataType);
/// Returns the data type of a data array depending on the number of components of the given data array:
static const DataType getDataType(vtkSmartPointer<vtkDataArray>);
/** Returns the data type string of an data array depending on the number of components of the given data array:
* If the number of components is different than 1, 3 and 9 (the managed type SCALARS, VECTORS, TENSORS)
* then the method returns a string equals to the number of components.
*/
static const QString getDataTypeName(vtkSmartPointer<vtkDataArray>);
/// Helper method that returns the RepresentationOf3DData as a QString
static const QString getRepresentationOf3DDataName (const RepresentationOf3DData );
/**
* @}
*/
......@@ -404,6 +473,27 @@ private:
/// combo box to select how to display data when then have 3 components
QComboBox* displayTypePolicyBox;
/// map of specific 3D Data representations
QMap<const QString &, vtkSmartPointer<vtkDataArray> > specific3DDataRepresentation;
/// map of visibility status of data
QMap<vtkSmartPointer<vtkDataArray>, bool> dataRepresentationVisibility;
// names of all the specific prop
QStringList dataPropNames;
/// create the data representation of a given data (identified with its name) of a given field type, default visibility is off
void createDataRepresentation(FieldType, const QString&, RepresentationOf3DData representation = HEDGE_HOG) ;
// Returns the very specific name used for the additional prop that represent this data
const QString getDataPropName(FieldType , const QString& );
/// initialize FieldType QString map
static QMap< int, QString > initFieldNames();
/// initialize DataType QString map
static QMap< int, QString > initDataNames();
/// action to remove data
QAction* removeData;
......
......@@ -58,22 +58,30 @@ int MeshDataModel::columnCount(const QModelIndex& parent) const {
return 3;
}
// -------------------- getFieldTypeOfRow --------------------
MeshDataModel::FieldType MeshDataModel::getFieldTypeOfRow(const int row, int* dataIndex) const {
int nbPointData = meshComponent->getPointSet()->GetPointData()->GetNumberOfArrays();
int nbCellData = meshComponent->getPointSet()->GetCellData()->GetNumberOfArrays();
// -------------------- getRowInfo --------------------
void MeshDataModel::getRowInfo(const int row, int* dataIndex, MeshComponent::FieldType *field, MeshComponent::DataType* type, QString & name) const {
int nbPointData = meshComponent->getNumberOfDataArray(MeshComponent::POINTS);
int nbCellData = meshComponent->getNumberOfDataArray(MeshComponent::CELLS);
if (row < nbPointData) {
*dataIndex = row;
return POINTS;
*field = MeshComponent::POINTS;
}
else if (row < (nbPointData + nbCellData)) {
*dataIndex = row - nbPointData;
return CELLS;
*field = MeshComponent::CELLS;
}
else {
*dataIndex = row - (nbPointData + nbCellData);
return MESH;
*field = MeshComponent::MESH;
}
if (*field != MeshComponent::MESH) {
vtkSmartPointer<vtkDataArray> dataArray = meshComponent->getDataArray(*field, *dataIndex);
name = dataArray->GetName();
*type = MeshComponent::getDataType(dataArray);
}
else {
*type = MeshComponent::OTHERS;
}
}
......@@ -87,14 +95,11 @@ QVariant MeshDataModel::data(const QModelIndex& index, int role) const {
int column = index.column();
int dataIndex;
FieldType fieldType = getFieldTypeOfRow(row, &dataIndex);
MeshComponent::FieldType fieldType;
MeshComponent::DataType type;
QString arrayName;
getRowInfo(row, &dataIndex,&fieldType, &type, arrayName);
// TODO use only MeshComponent methods
vtkSmartPointer<vtkFieldData> data = meshComponent->getFieldData(fieldType);
vtkSmartPointer<vtkDataArray> dataArray = data->GetArray(dataIndex);
DataType type = getDataType(dataArray);
QString arrayName = dataArray->GetName();
switch (role) {
case Qt::DisplayRole:
switch ( column ) {
......@@ -103,11 +108,11 @@ QVariant MeshDataModel::data(const QModelIndex& index, int role) const {
break;
case 1 :
return getFieldName(fieldType);
return MeshComponent::getFieldName(fieldType);
break;
case 2 :
return getDataTypeName(dataArray);
return MeshComponent::getDataTypeName(type);
break;
default:
......@@ -119,76 +124,24 @@ QVariant MeshDataModel::data(const QModelIndex& index, int role) const {
case Qt::CheckStateRole:
if ((column == 0) && fieldType != MESH) {
vtkSmartPointer<vtkDataSetAttributes> dataSetAttr = vtkDataSetAttributes::SafeDownCast(data); // only valid for point and cell data
switch (type) {
case SCALARS: {
vtkSmartPointer<vtkDataArray> currentlySelected = dataSetAttr->GetScalars();
// TODO use MeshComponent::isScalarDataVisible(arrayName)
if (currentlySelected && QString(currentlySelected->GetName()) == arrayName) {
return Qt::Checked;
}
else {
return Qt::Unchecked;
}
}
break;
case VECTORS: {
auto currentDisplayType = meshComponent->getCurrentDisplayTypePolicy();
// for 3D data status it depends on the current policy
if (currentDisplayType != HEDGE_HOG) {
// TODO use MeshComponent::is3DDataVisible
QString arrayToDisplay = QString("%1%2").arg(arrayName).arg(getDisplayTypeFor3DDataName(currentDisplayType));
if (dataSetAttr->HasArray(arrayToDisplay.toUtf8().constData())) {
vtkSmartPointer<vtkDataArray> dataArrayToDisplay = dataSetAttr->GetArray(arrayToDisplay.toUtf8().constData());
// if there is an array with this name, this means it is currently displayed
if (dataArrayToDisplay) {
return Qt::Checked;
}
else {
return Qt::Unchecked;
}
}
}
}
// else continue to the case where a prop might be available
case TENSORS: {
// The first time this method is call, the corresponding prop is created with visibility off
vtkSmartPointer<vtkProp> prop = meshComponent->getDataProp(fieldType, data->GetArray( dataIndex )->GetName());
if (prop) {
if (prop->GetVisibility()) {
return Qt::Checked;
}
else {
return Qt::Unchecked;
}
}
else
return Qt::Unchecked;
}
break;
default:
break;
if ((column == 0) && fieldType != MeshComponent::MESH) {
if (meshComponent->getDataRepresentationVisibility(fieldType,arrayName,meshComponent->getCurrentDisplayTypePolicy())) {
return Qt::Checked;
}
else {
return Qt::Unchecked;
}
}
break;
case Qt::DecorationRole :
switch (column) {
case 1:
switch (fieldType) {
case POINTS:
case MeshComponent::POINTS:
return QIcon(":/points");
break;
case CELLS:
case MeshComponent::CELLS:
return QIcon(":/cell");
break;
default:
......@@ -197,10 +150,10 @@ QVariant MeshDataModel::data(const QModelIndex& index, int role) const {
break;
case 2:
switch (type) {
case SCALARS:
case MeshComponent::SCALARS:
return QIcon(":/scalars");
break;
case VECTORS:
case MeshComponent::VECTORS:
return QIcon(":/vectors");
break;
default:
......@@ -231,19 +184,28 @@ bool MeshDataModel::setData(const QModelIndex& index, const QVariant& value, int
if (role == Qt::CheckStateRole && index.column() == 0) {
int row = index.row();
int dataIndex;
FieldType fieldType = getFieldTypeOfRow(row, &dataIndex);
MeshComponent::FieldType fieldType;
MeshComponent::DataType type;
QString arrayName;
getRowInfo(row, &dataIndex,&fieldType, &type, arrayName);
if (fieldType == MESH) {
if (fieldType == MeshComponent::MESH) {
// nothing to do if this is a MESH data
return false;
}
else {
vtkSmartPointer<vtkDataArray> dataArray = meshComponent->getDataArray(fieldType, dataIndex);
QString arrayName = dataArray->GetName();
MeshComponent::DataType type = meshComponent->getDataType(dataArray);
meshComponent->setDataRepresentationVisibility(fieldType,arrayName,(value == Qt::Checked),meshComponent->getCurrentDisplayTypePolicy());
/*
vtkSmartPointer<vtkFieldData> data = meshComponent->getFieldData(fieldType);
vtkSmartPointer<vtkDataArray> dataArray = data->GetArray(dataIndex);
QString arrayName = dataArray->GetName();
switch(getDataType(dataArray)) {
case SCALARS:
switch(meshComponent->getDataType(dataArray)) {
case MeshComponent::SCALARS:
// Classic 1D data, show/hide the corresponding data depending on check state
if (value == Qt::Checked) {
// TODO move this to MeshComponent::setScalarDataVisible
......@@ -253,22 +215,22 @@ bool MeshDataModel::setData(const QModelIndex& index, const QVariant& value, int
else {
// TODO move this to MeshComponent::setScalarDataVisible
// hide the data by setting no active fieldType data
meshComponent->setActiveData(fieldType, NULL);
meshComponent->setDataRepresentationOff();
}
break;
case VECTORS: {
case MeshComponent::VECTORS: {
// for 3D data with prop, check if the user wants a 3D representation or a specific 1D display type
auto currentDisplayType = meshComponent->getCurrentDisplayTypePolicy();
if (meshComponent->getCurrentDisplayTypePolicy() != HEDGE_HOG) {
if (meshComponent->getCurrentDisplayTypePolicy() != MeshComponent::HEDGE_HOG) {
// complicated name to avoid accidental override of user data
QString nameOfArrayToDisplay = QString("%1%2").arg(arrayName).arg(getDisplayTypeFor3DDataName(currentDisplayType));
QString nameOfArrayToDisplay = (arrayName + meshComponent->getRepresentationOf3DDataName (currentDisplayType));
// for 3D data create and show/hide the corresponding 1D data visualization depending on the current display type policy
if (value == Qt::Checked) {
double range[2]; // TODO move this with the rest to MeshComponent
// TODO use MeshComponent::is3DDataVisible(arrayName,DisplayTypeFor3DData):bool method to determine this
// TODO use MeshComponent::is3DDataVisible(arrayName,RepresentationOf3DData):bool method to determine this
// check if the array already exists and if it is currently displayed
if (!data->HasArray(nameOfArrayToDisplay.toUtf8().constData())) {
// TODO move this to MeshComponent::createExtraArray
......@@ -294,7 +256,7 @@ bool MeshDataModel::setData(const QModelIndex& index, const QVariant& value, int
}
// set it as active
// TODO move all these lines to MeshComponent (and remove the #include "InteractiveViewer.h" above
// → create method set3DDataVisible(arrayName,DisplayTypeFor3DData,bool):void
// → create method set3DDataVisible(arrayName,RepresentationOf3DData,bool):void
meshComponent->getPointSet()->GetPointData()->SetActiveScalars( nameOfArrayToDisplay.toUtf8().constData());
// update mapper range
meshComponent->setMapperScalarRange(range[0], range[1]);
......@@ -333,7 +295,7 @@ bool MeshDataModel::setData(const QModelIndex& index, const QVariant& value, int
}
break;
}
case TENSORS: {
case MeshComponent::TENSORS: {
vtkSmartPointer<vtkProp> prop = meshComponent->getDataProp(fieldType, arrayName);
// 9D data: show/hide the prop in 3D depending on check state
if (value == Qt::Checked) {
......@@ -349,38 +311,20 @@ bool MeshDataModel::setData(const QModelIndex& index, const QVariant& value, int
}
meshComponent->refresh();
*/
return true;
}
}
else {
return false;
}
}
// TODO in MeshComponent:
// 1. check if the helpers method written now are can be used to simplify MeshComponent code
// 2. MeshDataModel should be not be able to explore the point/cell/field data of MeshComponent, which should be the sole
// manager of that type of data.
// → Therefore, add the following method to MeshComponent and used them here:
//
// - getTypeOfArray
//
// - getDataProp that should only returns the prop if it already exists (and be kept only for compatibility reason / erase as a BDFL decision)
// - createDataProp to create a given prop
// - setDataPropVisibility
// - getDataPropVisibility
//
// - set3DDataVisibility(arrayName,DisplayTypeFor3DData,bool):void
// - get3DDataVisibility(arrayName,DisplayTypeFor3DData):bool (arrayName is the name of a 3D array), check if it exists and is currently displayed (it can exists but not be visible at the moment)
// - create3DData(arrayName,DisplayTypeFor3DData):void
//
// - setScalarDataVisible(arrayName,bool):void
// - getScalarDataVisibility(arrayName)
// -------------------- flags --------------------
Qt::ItemFlags MeshDataModel::flags(const QModelIndex& index) const {
if (index.column() == 0) {
return Qt::ItemIsSelectable | /* Qt::ItemIsEditable | */ Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
}
else {
return Qt::ItemIsSelectable | Qt::ItemIsEnabled ;
......@@ -421,110 +365,6 @@ void MeshDataModel::refresh() {
}
// -------------------- initFieldNames --------------------
QMap< int, QString > MeshDataModel::initFieldNames() {
QMap< int, QString > fieldNames;
fieldNames[MeshDataModel::POINTS] = "points";
fieldNames[MeshDataModel::CELLS] = "cells";
fieldNames[MeshDataModel::CELLS] = "mesh";
return fieldNames;
}
// -------------------- getFieldNames --------------------
const QMap< int, QString >& MeshDataModel::getFieldNames() {
static QMap<int, QString> fieldNames = initFieldNames();
return fieldNames;
}
// -------------------- getFieldName --------------------
const QString MeshDataModel::getFieldName (const FieldType fieldType) {
return getFieldNames