MeshComponent.cpp 40.2 KB
Newer Older
1
/*****************************************************************************
2
3
4
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
5
* (c) 2001-2017 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
*
* Visit http://camitk.imag.fr for more information
*
* This file is part of CamiTK.
*
* CamiTK is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* CamiTK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License version 3 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
*
* $CAMITK_LICENCE_END$
****************************************************************************/
25
26

#include "MeshComponent.h"
27
#include "InteractiveViewer.h"
28
#include "Property.h"
29
30
#include "Application.h"
#include "MeshDataModel.h"
31

32
33
34
35
//-- Qt stuff
#include <QMessageBox>
#include <QTextStream>
#include <QFileInfo>
36
#include <QTableView>
mat's avatar
mat committed
37
38
#include <QBoxLayout>
#include <QToolBar>
39
#include <QList>
40

41
42
//-- vtk stuff
#include <vtkPointSet.h>
43
44
45
46
47
48
#include <vtkUnstructuredGrid.h>
#include <vtkTetra.h>
#include <vtkHexahedron.h>
#include <vtkWedge.h>
#include <vtkPyramid.h>
#include <vtkCellArray.h>
49
#include <vtkGenericCell.h>
50
51
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
52
53
54
55
56
57
#include <vtkCellData.h>
#include <vtkPointData.h>
#include <vtkDataSetAttributes.h>
#include <vtkExtractSelection.h>
#include <vtkDataSetMapper.h>
#include <vtkProperty.h>
mat's avatar
mat committed
58
59
60
61
62
#include <vtkHedgeHog.h>
#include <vtkTensorGlyph.h>
#include <vtkActor.h>
#include <vtkSphereSource.h>
#include <vtkCellCenters.h>
63

64
namespace camitk {
mat's avatar
mat committed
65

66
// -------------------- constructor --------------------
67
MeshComponent::MeshComponent(const QString& file) throw (AbortException) : Component(file, "Mesh", Component::GEOMETRY) {
mat's avatar
mat committed
68
    init();
69
70
}

71
MeshComponent::MeshComponent(vtkSmartPointer<vtkPointSet> aPointSet, const QString& name) : Component("", name, Component::GEOMETRY) {
mat's avatar
mat committed
72
    init();
73
    initRepresentation(aPointSet);
74
    setModified();
75
76
}

77
MeshComponent::MeshComponent(Component* parentComponent, vtkSmartPointer<vtkPointSet> aPointSet, const QString& name) : Component(parentComponent, name, Component::GEOMETRY) {
mat's avatar
mat committed
78
    init();
79
    initRepresentation(aPointSet);
80
81
}

82
83
// -------------------- destructor --------------------
MeshComponent::~MeshComponent() {
84
    if (getPointSet() != NULL) {
85
        setDataRepresentationOff();
86
    }
87

88
    if (selectionWidget != nullptr) {
mat's avatar
mat committed
89
        delete selectionWidget;
90
    }
91

92
    if (dataWidget != nullptr) {
mat's avatar
mat committed
93
        delete dataWidget;
94
    }
95
96
}

mat's avatar
mat committed
97
void MeshComponent::init() {
98
99
    pickedCellId = -1;
    pickedPointId = -1;
mat's avatar
mat committed
100

mat's avatar
mat committed
101
102
    // selection widget
    selectionWidget = new QWidget();
103
    selectionWidget->setObjectName("Selection");
mat's avatar
mat committed
104
105

    // selection actions
106
107
108
109
    removeSelections = new QAction(QPixmap(":/delete"), tr("Remove selection(s)"), this);
    removeSelections->setStatusTip(tr("Remove the selected selections"));
    removeSelections->setWhatsThis(tr("Remove the selected selections"));
    connect(removeSelections, SIGNAL(triggered()), this, SLOT(removeSelectedSelections()));
mat's avatar
mat committed
110

111
112
113
    inspectSelection = new QAction(QPixmap(":/settings"), tr("Inspect the selection"), this);
    inspectSelection->setStatusTip(tr("Inspect the selection"));
    inspectSelection->setWhatsThis(tr("Inspect the selection"));
mat's avatar
mat committed
114

115
116
117
    mergeSelection = new QAction(QPixmap(":/refresh"), tr("Merge the selections"), this);
    mergeSelection->setStatusTip(tr("Merge the selected selection"));
    mergeSelection->setWhatsThis(tr("Merge the selected delections (selection types must be identical)"));
mat's avatar
mat committed
118
119

    // selection model
120
    selectionModel = new MeshSelectionModel(this);
mat's avatar
mat committed
121

mat's avatar
mat committed
122
    // selection view
123
124
125
126
127
128
    selectionView = new MeshSelectionView(selectionWidget);
    selectionView->setSelectionBehavior(QAbstractItemView::SelectRows);
    selectionView->setModel(selectionModel);
    selectionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    selectionView->setEditTriggers(QAbstractItemView::DoubleClicked);

129
130
131
132
133
134
135
    insertionPolicyBox = new QComboBox(selectionView);
    insertionPolicyBox->setStatusTip(tr("Insertion policy"));
    insertionPolicyBox->setWhatsThis(tr("Insertion policy"));
    insertionPolicyBox->addItem("Replace", MeshSelectionModel::REPLACE);
    insertionPolicyBox->addItem("Merge", MeshSelectionModel::MERGE);
    insertionPolicyBox->addItem("Substract", MeshSelectionModel::SUBSTRACT);
    insertionPolicyBox->addItem("Discard", MeshSelectionModel::DISCARD);
mat's avatar
mat committed
136
137

    // build the selection widget
138
139
    QVBoxLayout* hbox = new QVBoxLayout(selectionWidget);
    QToolBar* selectionToolBar = new QToolBar(selectionWidget);
140
141
142
    selectionToolBar->addAction(removeSelections);
    selectionToolBar->addAction(mergeSelection);
    selectionToolBar->addAction(inspectSelection);
143
    selectionToolBar->addWidget( insertionPolicyBox );
144
145
146
    hbox->addWidget(selectionView);
    hbox->addWidget(selectionToolBar);
    selectionWidget->setLayout(hbox);
mat's avatar
mat committed
147
148
149
150
151
152

    // data widget
    dataWidget = new QWidget();
    dataWidget->setObjectName("Data");

    // selection actions
153
154
155
156
    removeData = new QAction(QPixmap(":/delete"), tr("Remove data"), this);
    removeData->setStatusTip(tr("Remove the selected data"));
    removeData->setWhatsThis(tr("Remove the selected data"));
    connect(removeData, SIGNAL(triggered()), this, SLOT(removeSelectedData()));
mat's avatar
mat committed
157

158
159
160
    inspectData = new QAction(QPixmap(":/settings"), tr("Inspect data"), this);
    inspectData->setStatusTip(tr("Inspect data"));
    inspectData->setWhatsThis(tr("Inspect data"));
mat's avatar
mat committed
161
162

    // data model
163
    dataModel = new MeshDataModel(this);
mat's avatar
mat committed
164
165
166

    // data view
    dataView = new MeshDataView();
167
168
169
    dataView->setSelectionBehavior(QAbstractItemView::SelectRows);
    dataView->setModel(dataModel);
    dataView->setSelectionMode(QAbstractItemView::ExtendedSelection);
170

171
172
173
    displayTypePolicyBox = new QComboBox(dataView);
    displayTypePolicyBox->setStatusTip(tr("Display type policy for 3D data"));
    displayTypePolicyBox->setWhatsThis(tr("Display type policy for 3D data"));
174
175
176
177
178
    displayTypePolicyBox->addItem("3D Vector", HEDGE_HOG);
    displayTypePolicyBox->addItem("Norm", NORM);
    displayTypePolicyBox->addItem("1st Component", FIRST_COMPONENT);
    displayTypePolicyBox->addItem("2nd Component", SECOND_COMPONENT);
    displayTypePolicyBox->addItem("3nd Component", THIRD_COMPONENT);
179
    
mat's avatar
mat committed
180
    // build the data widget
181
182
    QVBoxLayout* dataBox = new QVBoxLayout(dataWidget);
    QToolBar* dataToolBar = new QToolBar(dataWidget);
183
184
    dataToolBar->addAction(removeData);
    dataToolBar->addAction(inspectData);
185
    dataToolBar->addWidget(displayTypePolicyBox);
186
187
188
    dataBox->addWidget(dataView);
    dataBox->addWidget(dataToolBar);
    dataWidget->setLayout(dataBox);
mat's avatar
mat committed
189

190
    connect(selectionView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(changeSelectedSelection(const QItemSelection&, const QItemSelection&)));
191

192
193
    // selection
    currentSelection = vtkSmartPointer<vtkSelection>::New();
mat's avatar
mat committed
194
195
196
}

// -------------------- initRepresentation --------------------
197
void MeshComponent::initRepresentation(vtkSmartPointer<vtkPointSet> originalPointSet) {
198
    // if there is no point set yet, just do nothing
199
    if (originalPointSet == NULL) {
200
        return;
201
    }
202

203
    // else replace the point set
204
205
    if (myGeometry) {
        myGeometry->setPointSet(originalPointSet);
206
207
    }
    else {
208
209
210
211
        myGeometry = new Geometry(this->getName(), originalPointSet);
    }

    myGeometry->setMeshWorldTransform(getTransformFromWorld());
Emmanuel Promayon's avatar
Emmanuel Promayon committed
212
    
promayon's avatar
promayon committed
213
    // add it in the InteractiveViewer (automatically)
214
    setVisibility(InteractiveViewer::get3DViewer(), true);
mat's avatar
mat committed
215

mat's avatar
mat committed
216
217
218
219
220
221
222
223
224
225
    // initialize selection
    initSelection();

    // initialize data
    initData();

    // initialize dynamic properties
    initDynamicProperties();
}

226
// -------------------- initSelection --------------------
mat's avatar
mat committed
227
void MeshComponent::initSelection() {
228
229
230
    vtkSmartPointer<vtkExtractSelection> selectionExtractor = vtkSmartPointer<vtkExtractSelection>::New();
    vtkSmartPointer<vtkActor> selectionActor = vtkSmartPointer<vtkActor>::New();
    vtkSmartPointer<vtkDataSetMapper> selectionMapper = vtkSmartPointer<vtkDataSetMapper>::New();
231

232
    selectionExtractor->SetInputConnection(0, this->getDataPort());
233
    selectionExtractor->SetInputData(1, currentSelection);
234

235
    selectionMapper->SetInputConnection(selectionExtractor->GetOutputPort());
236

237
    selectionActor->SetPickable(false);
238
    selectionActor->GetProperty()->SetRepresentationToSurface();
239
240
241
242
243
    selectionActor->GetProperty()->SetLineWidth(5);
    selectionActor->GetProperty()->SetColor(1, 0, 0);
    selectionActor->GetProperty()->SetPointSize(10);
    selectionActor->GetProperty()->SetOpacity(0.2);
    selectionActor->SetMapper(selectionMapper);
244

245
    addProp("Selection", selectionActor);
mat's avatar
mat committed
246
}
247

248
// -------------------- initData --------------------
mat's avatar
mat committed
249
250
void MeshComponent::initData() {
    dataModel->refresh();
251
252
}

253
// -------------------- cellPicked --------------------
254
void MeshComponent::cellPicked(vtkIdType cellId, bool) {
255
256
257
258
    pickedCellId = cellId;
}

// -------------------- pointPicked --------------------
259
void MeshComponent::pointPicked(vtkIdType pointId, bool) {
260
261
262
263
264
265
266
267
268
269
270
271
    pickedPointId = pointId;
}

// -------------------- getPickedCellId --------------------
vtkIdType MeshComponent::getPickedCellId() {
    return pickedCellId;
}

// -------------------- getPickedPointId --------------------
vtkIdType MeshComponent::getPickedPointId() {
    return pickedPointId;
}
272

273
274
275
// -------------------- initDynamicProperties --------------------
void MeshComponent::initDynamicProperties() {
    vtkIdType count = 0;
276

277
    if (getPointSet() != NULL) {
278
        count = getPointSet()->GetNumberOfPoints();
279
    }
280

281
    Property* nbPoints = new Property("Number Of Points", QVariant(QString("%1").arg(count)), "Number of 3D Points composing the geometry", "");
282
283
284
    nbPoints->setReadOnly(true);
    addProperty(nbPoints);

285
    if (getPointSet() != NULL) {
286
        count = getPointSet()->GetNumberOfCells();
287
    }
288

289
    Property* nbCells = new Property("Number Of Cells", QVariant(QString("%1").arg(count)), "Number of Cells composing the geometry", "");
290
291
292
293
    nbCells->setReadOnly(true);
    addProperty(nbCells);

    if (getPointSet() != NULL) {
294
        // add a dynamic property to manage the surface color
295
        // setProperty("position point #1", QVector3D(1.0,0.0,0.0));
mat's avatar
mat committed
296
        vtkSmartPointer<vtkGenericCell> cell = vtkGenericCell::New();
297
298
299
        std::map<unsigned char, int> elementsMap;
        std::map<unsigned char, int>::iterator elementsMapIt;

300
301
        for (int i = 0; i < getPointSet()->GetNumberOfCells(); i++) {
            getPointSet()->GetCell(i, cell);
302

303
            if (!elementsMap.count(cell->GetCellType())) {
304
                elementsMap[ cell->GetCellType()] = 0;
305
            }
306

307
308
309
310
            elementsMap[ cell->GetCellType() ]++;

        }

311
        // the list of all possible cell types is defined in VTKCellType enum of the VTKCellType class
312
        for (elementsMapIt = elementsMap.begin(); elementsMapIt != elementsMap.end(); elementsMapIt++) {
313
            Property* cellProp;
314
315

            switch (elementsMapIt->first) {
316
317
318
                case VTK_EMPTY_CELL:
                    cellProp = new Property("Empty Cells", elementsMapIt->second, tr("Number Of Empty Cells"), "");
                    break;
319

320
321
322
                case VTK_VERTEX:
                    cellProp = new Property("Vertex", elementsMapIt->second, tr("Number Of Vertex Cells"), "");
                    break;
323

324
325
326
                case VTK_POLY_VERTEX:
                    cellProp = new Property("Edges", elementsMapIt->second, tr("Number Of Edge Cells"), "");
                    break;
327

328
329
330
                case VTK_LINE :
                    cellProp = new Property("Lines", elementsMapIt->second, tr("Number Of Line Cells"), "");
                    break;
331

332
333
334
                case VTK_POLY_LINE:
                    cellProp = new Property("Polylines", elementsMapIt->second, tr("Number Of Polylines Cells"), "");
                    break;
335

336
337
338
                case VTK_TRIANGLE :
                    cellProp = new Property("Triangles", elementsMapIt->second, tr("Number Of Triangle Cells"), "");
                    break;
339

340
341
342
                case VTK_TRIANGLE_STRIP:
                    cellProp = new Property("Triangle Strips", elementsMapIt->second, tr("Number Of Triangle Strip Cells"), "");
                    break;
343

344
345
346
                case VTK_POLYGON:
                    cellProp = new Property("Polygons", elementsMapIt->second, tr("Number Of Polygon Cells"), "");
                    break;
347

348
349
350
                case VTK_PIXEL:
                    cellProp = new Property("Pixels", elementsMapIt->second, tr("Number Of Pixel Cells"), "");
                    break;
351

352
353
354
                case VTK_QUAD:
                    cellProp = new Property("Quads", elementsMapIt->second, tr("Number Of Quad Cells"), "");
                    break;
355

356
357
358
                case VTK_TETRA :
                    cellProp = new Property("Tetrahedra", elementsMapIt->second, tr("Number Of Tetrahedral Cells"), "");
                    break;
359

360
361
362
                case VTK_VOXEL:
                    cellProp = new Property("Voxels", elementsMapIt->second, tr("Number Of Voxel Cells"), "");
                    break;
363

364
365
366
                case VTK_HEXAHEDRON :
                    cellProp = new Property("Hexahedra", elementsMapIt->second, tr("Number Of Hexahedral Cells"), "");
                    break;
367

368
369
370
                case VTK_WEDGE :
                    cellProp = new Property("Wedges", elementsMapIt->second, tr("Number Of Wedge Cells"), "");
                    break;
371

372
373
374
                case VTK_PYRAMID :
                    cellProp = new Property("Pyramids", elementsMapIt->second, tr("Number Of Pyramid Cells"), "");
                    break;
375

376
377
378
                case VTK_PENTAGONAL_PRISM:
                    cellProp = new Property("Pentagonal Prisms", elementsMapIt->second, tr("Number Of Pentagonal Prism Cells"), "");
                    break;
379

380
381
382
                case VTK_HEXAGONAL_PRISM:
                    cellProp = new Property("Hexagonal Prisms", elementsMapIt->second, tr("Number Of Hexagonal Prism Cells"), "");
                    break;
383

384
385
386
                default:
                    cellProp = new Property("Others", elementsMapIt->second, tr("Number Of <i>Other Type Of Cells</i>. <br/>It can be quadratic isoparametric cells, Cubic isoparametric cells, <br/>convex group of points, higher order cells in parametric form, <br/>higher order cells (see VTKCellType enum for more information)"), "");
                    break;
387
            }
388
389
390

            cellProp->setReadOnly(true);
            addProperty(cellProp);
391
392
        }
    }
393
394

    unsigned long memUsage = 0;
395

396
    if (getPointSet() != NULL) {
397
        memUsage = getPointSet()->GetActualMemorySize();
398
    }
399

400
    Property* memoryUsage = new Property("Size In Memory", QVariant(QString("%1").arg(memUsage)), tr("Actual size of the data in kilobytes. <br/>This number is valid only after the pipeline has updated. <br/>The memory size returned is guaranteed to be greater than or <br/>equal to the memory required to represent the data<br/> (e.g., extra space in arrays, etc. are not included in the return value)."), "Kb");
401
402
    memoryUsage->setReadOnly(true);
    addProperty(memoryUsage);
mat's avatar
mat committed
403
}
404
405

// -------------------- getSelections --------------------
406
QList< vtkSmartPointer< vtkSelectionNode > >& MeshComponent::getSelections() {
mat's avatar
mat committed
407
    return selectionList;
408
409
}

410
411
// -------------------- getNumberOfSelections --------------------
unsigned int MeshComponent::getNumberOfSelections() const {
412
    return selectionList.size();
413
414
}

415
// -------------------- getActiveSelection --------------------
mat's avatar
mat committed
416
417
vtkSmartPointer<vtkSelection> MeshComponent::getActiveSelection() const {
    return currentSelection;
418
419
}

420
// -------------------- getSelection --------------------
421
vtkSmartPointer< vtkSelectionNode > MeshComponent::getSelection(const QString& name) const {
422
423
    int indexOfSelection = getSelectionIndex(name);

424
    if (indexOfSelection >= 0 && indexOfSelection < selectionList.size()) {
425
        return getSelectionAt(indexOfSelection);
426
427
    }
    else {
428
        return NULL;
429
    }
430
431
}

432
433
// -------------------- getSelectionAt --------------------
vtkSmartPointer< vtkSelectionNode > MeshComponent::getSelectionAt(unsigned int index) const {
mat's avatar
mat committed
434
    return selectionList.at(index);
435
436
}

437
// -------------------- getSelectionIndex --------------------
438
int MeshComponent::getSelectionIndex(const QString& name) const {
mat's avatar
mat committed
439
    QList< vtkSmartPointer< vtkSelectionNode > >::const_iterator it = selectionList.constBegin();
440
441
442
443
    int index = 0;
    bool found = false;

    while (it != selectionList.end() && !found) {
444
        if ((*it)->GetSelectionList() && !QString::compare(QString((*it)->GetSelectionList()->GetName()), name)) {
445
            found = true;
446
        }
447
448
449
450
        else {
            index++;
            it++;
        }
mat's avatar
mat committed
451
    }
452

453
    if (found) {
454
        return index;
455
456
    }
    else {
457
        return -1;
458
    }
mat's avatar
mat committed
459
460
}

461
// -------------------- addSelection --------------------
462
int MeshComponent::addSelection(const QString& name, int fieldType, int contentType, vtkSmartPointer< vtkAbstractArray > array, MeshSelectionModel::InsertionPolicy policy) {
463
    int index = selectionModel->insertSelection(name, fieldType, contentType, array, policy);
mat's avatar
mat committed
464
465
466
    return index;
}

467
468
// -------------------- addToSelectedSelection --------------------
int MeshComponent::addToSelectedSelection(int fieldType, int contentType, vtkSmartPointer< vtkAbstractArray > array, MeshSelectionModel::InsertionPolicy policy) {
mat's avatar
mat committed
469
470
471
472
    // use the current index to handle the case of multiple selection
    int index = selectionView->selectionModel()->currentIndex().row();

    // TODO : for now, we don't care about the policy parameter and use the one of the combo box
473
    // but in the future, the policy should be selected by pressing modifiers keys
474
    policy = (MeshSelectionModel::InsertionPolicy) insertionPolicyBox->itemData( insertionPolicyBox->currentIndex()).toInt();
mat's avatar
mat committed
475
476

    // check if the current selection is selected (maybe it is not necessary ...)
477
    if (selectionView->selectionModel()->isRowSelected(index, QModelIndex())) {
478
        index = addSelection(selectionList.at(index)->GetSelectionList()->GetName(), fieldType, contentType, array, policy);
479
480
    }
    else {
481
        index = addSelection("Picked Selection", fieldType, contentType, array, policy);
482
    }
mat's avatar
mat committed
483
484
485
486

    // forced clearing even if the selected index stay the same
    // if not, display will not be updated
    selectionView->clearSelection();
487
    // select the added selection and set the current index
488
    selectionView->selectionModel()->setCurrentIndex(selectionModel->index(index, 0, QModelIndex()), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
mat's avatar
mat committed
489
490

    return index;
mat's avatar
mat committed
491
492
}

493
// -------------------- changeSelectedSelection --------------------
mat's avatar
mat committed
494
// TODO : rename updateSelection
495
void MeshComponent::changeSelectedSelection(const QItemSelection& selected, const QItemSelection& deselected) {
mat's avatar
mat committed
496
    // remove all the selection nodes from the selection
497
498
    currentSelection->RemoveAllNodes();

mat's avatar
mat committed
499
500
501
502
    // do not use selected since it contains only the new selected selections
    // QModelIndexList items = selected.indexes();
    QModelIndex index;
    QModelIndexList items = selectionView->selectionModel()->selectedRows();
503
504

    // Select the PropertyExplorer 'Selection' tab for the currently selected component
505
    if (!Application::getSelectedComponents().isEmpty()) {
506
        Component* currentComponent = Application::getSelectedComponents().last();
507
        currentComponent->setIndexOfPropertyExplorerTab(1);
mat's avatar
mat committed
508
509
510
    }

    // add each selected selection nodes to the current selection
511
512
    foreach (index, items) {
        currentSelection->Union(selectionList.at(index.row()));
513
514
515
    }

    this->refresh();
mat's avatar
mat committed
516

517
518
}

mat's avatar
mat committed
519
520
521
522
// -------------------- removeSelectedSelection --------------------
void MeshComponent::removeSelectedSelections() {
    // TODO : handle multiple selection
    int index = selectionView->selectionModel()->currentIndex().row();
523

524
    if (selectionView->selectionModel()->isRowSelected(index, QModelIndex())) {
525
        selectionModel->removeSelection(selectionList.at(index)->GetSelectionList()->GetName());
526
    }
527
528
}

529
// -------------------- getNumberOfDataArray --------------------
530
int MeshComponent::getNumberOfDataArray(int fieldFlag) {
531
532
533
534
    if (getPointSet() == NULL) {
        return 0;
    }
    else {
535
536
537
538
539
540
541
542
543
544
545
546
        int count = 0;
        if (fieldFlag & POINTS) {
            // remove specific representation
            count += + getPointSet()->GetPointData()->GetNumberOfArrays() - specific3DDataRepresentation.size();
        }
        if (fieldFlag & CELLS) {
            count += getPointSet()->GetCellData()->GetNumberOfArrays();
        }
        if (fieldFlag & MESH) {
            count += getPointSet()->GetFieldData()->GetNumberOfArrays();
        }
        return count;
547
548
549
    }
}

550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
// -------------------- createDataRepresentation --------------------
void MeshComponent::createDataRepresentation(FieldType field, const QString& name, RepresentationOf3DData representation) {
    vtkSmartPointer<vtkDataArray> dataArray = getDataArray(field,name);
    
    if (dataArray != nullptr) {
        // create the representation depending on the type
        DataType dataType = getDataType(dataArray);
        switch(dataType) {
            case SCALARS:
                // nothing to do, scalar data already preseng in the array and representation managed by the mapper
                break;
            case VECTORS:
                switch(representation) {
                    case HEDGE_HOG: {
                        // add the corresponding prop, but not visible
                        vtkSmartPointer<vtkHedgeHog> hedgeHog = vtkSmartPointer<vtkHedgeHog>::New();
                        vtkSmartPointer<vtkDataSetMapper> dataMapper = vtkSmartPointer< vtkDataSetMapper >::New();
                        vtkSmartPointer<vtkActor> dataActor = vtkSmartPointer< vtkActor >::New();

                        if (field == POINTS) {
                            hedgeHog->SetInputConnection(myGeometry->getDataPort());
                            hedgeHog->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name.toUtf8().constData());
                        }
                        else if (field == CELLS) {
                            vtkSmartPointer<vtkCellCenters> cellCentersFilter = vtkSmartPointer<vtkCellCenters>::New();
                            cellCentersFilter->SetInputConnection(myGeometry->getDataPort());
                            hedgeHog->SetInputConnection(cellCentersFilter->GetOutputPort());
                            hedgeHog->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, name.toUtf8().constData());
                        }
                        dataMapper->SetInputConnection(hedgeHog->GetOutputPort());
                        dataActor->SetMapper(dataMapper);
                        dataActor->GetProperty()->SetColor(0, 1, 0);
                        dataActor->VisibilityOff();

                        dataPropNames.append(getDataPropName(field, name));
                        addProp(getDataPropName(field, name), dataActor);
                    }
                    break;
                    default:
                        // 1D representation
                        // TODO
                        break;
                }
                break;
            case TENSORS: {
                vtkSmartPointer<vtkTensorGlyph> tensorGlyph = vtkSmartPointer<vtkTensorGlyph>::New();
                vtkSmartPointer<vtkDataSetMapper> dataMapper = vtkSmartPointer< vtkDataSetMapper >::New();
                vtkSmartPointer<vtkActor> dataActor = vtkSmartPointer< vtkActor >::New();
                vtkSmartPointer<vtkSphereSource> glyphSphere = vtkSmartPointer<vtkSphereSource>::New();
                glyphSphere->SetRadius(myGeometry->getBoundingRadius() / 50.0);
                
                if (field == POINTS) {
                    tensorGlyph->SetInputConnection(myGeometry->getDataPort());
                    tensorGlyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name.toUtf8().constData());
                }
                else if (field == CELLS) {
                    vtkSmartPointer<vtkCellCenters> cellCentersFilter = vtkSmartPointer<vtkCellCenters>::New();
                    cellCentersFilter->SetInputConnection(myGeometry->getDataPort());
                    tensorGlyph->SetInputConnection(cellCentersFilter->GetOutputPort());
                    tensorGlyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, name.toUtf8().constData());
                }
                
                tensorGlyph->SetSourceConnection(glyphSphere->GetOutputPort());
                tensorGlyph->SetColorModeToEigenvalues();
                tensorGlyph->SetExtractEigenvalues(false);
                tensorGlyph->SetScaling(1);
                tensorGlyph->SetMaxScaleFactor(2);
                tensorGlyph->SetClampScaling(1);
                dataMapper->SetInputConnection(tensorGlyph->GetOutputPort());
                dataActor->SetMapper(dataMapper);
                dataActor->GetProperty()->SetColor(0, 1, 0);
                dataActor->VisibilityOff();

                dataPropNames.append(getDataPropName(field, name));
                addProp(getDataPropName(field, name), dataActor);                
                }
                break;
            default:
                break;
        }
    }
}
    
// -------------------- getDataRepresentationVisibility --------------------
bool MeshComponent::getDataRepresentationVisibility(FieldType field, const QString&  name, RepresentationOf3DData representation) {
    if (representation == HEDGE_HOG) {
        return dataRepresentationVisibility.value(getDataArray(field,name));
    }
638
    else {
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
        // if this is a specific data representation, then check if the specific data array exists first
        if (specific3DDataRepresentation.contains(name + getRepresentationOf3DDataName(representation))) {
            return dataRepresentationVisibility.value(specific3DDataRepresentation.value(name + getRepresentationOf3DDataName(representation)));
        }
        else {
            return false;
        }
    }
}


// -------------------- setDataRepresentationOff --------------------
void MeshComponent::setDataRepresentationOff(int dataType) {
    if (dataType & SCALARS) {
        // update the visibility flag of all scalar data
        auto it = dataRepresentationVisibility.constBegin();
        while (it != dataRepresentationVisibility.constEnd()) {
            if (getDataType(it.key()) == SCALARS) {
                dataRepresentationVisibility.insert(it.key(),false);
            }
            ++it;
        }
        // update all data sets
        vtkSmartPointer< vtkDataSetAttributes > dataSet = vtkDataSetAttributes::SafeDownCast(getFieldData(POINTS));
        dataSet->SetActiveScalars(NULL);
        dataSet = vtkDataSetAttributes::SafeDownCast(getFieldData(CELLS));
        dataSet->SetActiveScalars(NULL);
        // remove all color bar 
        InteractiveViewer::get3DViewer()->setColorScaleTitle("");
        InteractiveViewer::get3DViewer()->setColorScale(false);
    
        refresh();
    }
    
    if ((dataType & VECTORS) || (dataType & TENSORS)) {
        for (int i = 0; i < dataPropNames.size(); ++i) {
            getProp(dataPropNames.at(i))->VisibilityOff();
        }
    }

    // refresh the property tab
    dataModel->refresh();
    
}
        
// -------------------- setDataRepresentationVisibility --------------------
void MeshComponent::setDataRepresentationVisibility(FieldType fieldType, const QString&  name, bool visibility, RepresentationOf3DData representation) {
    // currently not managed 
    if (fieldType == MESH)
        return;
    
    vtkSmartPointer< vtkDataSetAttributes > dataSet = vtkDataSetAttributes::SafeDownCast(getFieldData(fieldType));
    vtkSmartPointer<vtkDataArray> dataArray = getDataArray(fieldType, name);
    
    if (dataArray == nullptr) {
        setDataRepresentationOff(); // all off
        return;
    }
    
    if (!visibility) {
        setDataRepresentationOff(getDataType(dataArray));
    }
    else {
        switch (getDataType(dataArray)) {
            case SCALARS: {
                // update visibility status
                dataRepresentationVisibility.insert(dataArray,true);
                
                // not need to create the representation as the mapper can already handle scalar data
                
                // update the data set state
                dataSet->SetActiveScalars(name.toStdString().c_str());

                // update mapper range
                double range[2];
                dataSet->GetScalars()->GetRange(range); // range of the 1st component = unique component
                setMapperScalarRange(range[0], range[1]);
            
                //-- show the color scale in 3D
                InteractiveViewer::get3DViewer()->setColorScale(true);
                InteractiveViewer::get3DViewer()->setColorScaleTitle(name);
                InteractiveViewer::get3DViewer()->setColorScaleMinMax(range[0], range[1]);
            }
            break;

            case VECTORS: {
                // update the data set state
                dataSet->SetActiveVectors(name.toStdString().c_str());
                
                // check if the representation exists, if not create it an show it
                switch(representation) {
                    case HEDGE_HOG:
                        if (!dataRepresentationVisibility.contains(dataArray)) {
                            createDataRepresentation(fieldType, name);
                        }
                        
                        // update visibility status
                        dataRepresentationVisibility.insert(dataArray,true);
                        
                        // TODO show the representation
                        
                        break;
                    default:
                        // 1D representation
                        if (!specific3DDataRepresentation.value(name + getRepresentationOf3DDataName(representation))) {
                            createDataRepresentation(fieldType, name, representation);
                        }
                        // update visibility status
                        dataRepresentationVisibility.insert(specific3DDataRepresentation.value(name + getRepresentationOf3DDataName(representation)),true);

                        // TODO show the representation
                        break;
                }
                
            }
            break;

            case TENSORS:
                // TODO show the representation
                dataSet->SetActiveTensors(name.toStdString().c_str());
                break;

            default:
                break;
        }
        
    }

    // refresh the table
    dataModel->refresh();
    
}
    
772
// -------------------- getDataArray --------------------
773
vtkSmartPointer<vtkDataArray> MeshComponent::getDataArray(FieldType fieldType, const QString& arrayName) {
mat's avatar
mat committed
774
775
776
    vtkSmartPointer< vtkFieldData > dataField;

    switch (fieldType) {
777
        case POINTS :
778
779
            dataField = getPointSet()->GetPointData();
            break;
780

781
        case CELLS :
782
783
            dataField = getPointSet()->GetCellData();
            break;
784

785
        case MESH :
786
787
            dataField = getPointSet()->GetFieldData();
            break;
788

789
790
791
        default:
            dataField = NULL;
            break;
792
    }
mat's avatar
mat committed
793

794
    return dataField->GetArray(arrayName.toStdString().c_str());
mat's avatar
mat committed
795
796
}

797
vtkSmartPointer<vtkDataArray> MeshComponent::getDataArray(FieldType fieldType, int index) {
mat's avatar
mat committed
798
799
800
    vtkSmartPointer< vtkFieldData > dataField;

    switch (fieldType) {
801
        case POINTS :
802
803
            dataField = getPointSet()->GetPointData();
            break;
804

805
        case CELLS :
806
807
            dataField = getPointSet()->GetCellData();
            break;
808

809
        case MESH :
810
811
            dataField = getPointSet()->GetFieldData();
            break;
812

813
814
815
        default:
            dataField = NULL;
            break;
816
    }
mat's avatar
mat committed
817

818
    return dataField->GetArray(index);
819
820
}

mat's avatar
mat committed
821
// -------------------- addDataArray --------------------
822
void MeshComponent::addDataArray(FieldType fieldType, const QString& name, vtkSmartPointer< vtkDataArray > data) {
823
824

    // get the field data set attributes
mat's avatar
mat committed
825
826
827
    vtkSmartPointer< vtkFieldData > dataField;

    switch (fieldType) {
828
        case POINTS :
829
830
            dataField = getPointSet()->GetPointData();
            break;
mat's avatar
mat committed
831

832
        case CELLS :
833
834
            dataField = getPointSet()->GetCellData();
            break;
mat's avatar
mat committed
835

836
        case MESH :
837
838
            dataField = getPointSet()->GetFieldData();
            break;
mat's avatar
mat committed
839

840
841
842
        default:
            dataField = NULL;
            break;
mat's avatar
mat committed
843
844
    }

845
846
847
    // attach the new data
    data->SetName(name.toStdString().c_str());
    dataField->AddArray(data);
mat's avatar
mat committed
848

849
    // set the data as active
850
851
    setDataRepresentationVisibility(fieldType, name, true);
    
852
853
}

mat's avatar
mat committed
854
// -------------------- removeDataArray --------------------
855
void MeshComponent::removeDataArray(FieldType fieldType, const QString& name) {
mat's avatar
mat committed
856
857
858
    vtkSmartPointer< vtkFieldData > dataField;

    switch (fieldType) {
859
        case POINTS :
860
861
            dataField = getPointSet()->GetPointData();
            break;
862

863
        case CELLS :
864
865
            dataField = getPointSet()->GetCellData();
            break;
866

867
        case MESH :
868
869
            dataField = getPointSet()->GetFieldData();
            break;
870

871
872
873
        default:
            dataField = NULL;
            break;
mat's avatar
UPDATED    
mat committed
874
    }
mat's avatar
mat committed
875
876

    if (dataField->HasArray(name.toStdString().c_str())) {
877
        setDataRepresentationOff();
mat's avatar
mat committed
878
        dataField->RemoveArray(name.toStdString().c_str());
879
880
        removeProp(getDataPropName(fieldType, name));
        dataPropNames.removeAll(getDataPropName(fieldType, name));
mat's avatar
mat committed
881
    }
882

883
884
}

885
// -------------------- addPointData --------------------
886
void MeshComponent::addPointData(const QString& name, vtkSmartPointer< vtkDataArray > data) {
887
    addDataArray(POINTS, name, data);
888
889
}

890
// -------------------- addCellData --------------------
891
void MeshComponent::addCellData(const QString& name, vtkSmartPointer< vtkDataArray > data) {
892
    addDataArray(CELLS, name, data);
mat's avatar
mat committed
893
894
}

895
// -------------------- setActiveData --------------------
896
897
void MeshComponent::setActiveData(FieldType fieldType, const char* name) {
    setDataRepresentationVisibility(fieldType, name, true);
898
899
}

900
901
902
903
// -------------------- getDataPropName --------------------
const QString MeshComponent::getDataPropName(FieldType fieldType, const QString& arrayName) {
    // very specific name to avoid accidental override of user prop
    return QString(getName() + " representation of data array " + arrayName + " in " + getFieldName(fieldType) + " data");
mat's avatar
mat committed
904
905
}

906
// -------------------- getCurrentDisplayTypePolicy --------------------
907
908
MeshComponent::RepresentationOf3DData MeshComponent::getCurrentDisplayTypePolicy() const {
    return (RepresentationOf3DData ) displayTypePolicyBox->itemData(displayTypePolicyBox->currentIndex()).toInt();
909
910
911
912
913
914
}

// -------------------- getDataModel --------------------
MeshDataModel* MeshComponent::getDataModel() {
    return dataModel;
}
915

916
// -------------------- getFieldData --------------------
917
vtkSmartPointer<vtkFieldData> MeshComponent::getFieldData(FieldType fieldType) {
918
    switch (fieldType) {
919
        case POINTS:
920
921
922
            return getPointSet()->GetPointData();
            break;

923
        case CELLS:
924
925
926
            return getPointSet()->GetCellData();
            break;
            
927
        case MESH:
928
929
930
931
932
933
934
        default:
            return getPointSet()->GetFieldData();
            break;
    }
    
}

935
// -------------------- removeSelectedData --------------------
mat's avatar
mat committed
936
void MeshComponent::removeSelectedData() {
937
938
    // TODO : handle multiple selection and cell/mesh data array deletion
    int index = dataView->selectionModel()->currentIndex().row();
mat's avatar
mat committed
939

940
    if (dataView->selectionModel()->isRowSelected(index, QModelIndex())) {
941
        vtkSmartPointer<vtkDataArray> arrayToDelete = getDataArray(POINTS, index);
942
943
944

        if (!arrayToDelete)
            CAMITK_WARNING("MeshComponent", "removeSelectedData", "Removal of data #" << index << " not implemented yet")
945
            else {
946
                removeDataArray(POINTS, arrayToDelete->GetName());
947
            }
948
    }
949
950
}

951
// -------------------- getNumberOfPropertyWidget --------------------
mat's avatar
mat committed
952
953
954
955
unsigned int MeshComponent::getNumberOfPropertyWidget() {
    return 3;
}

956
// -------------------- getPropertyWidgetAt --------------------
957
QWidget* MeshComponent::getPropertyWidgetAt(unsigned int i, QWidget* parent) {
958
    switch (i) {
959
960
961
        case 0 :
            return this->getPropertyWidget();
            break;
962

963
964
965
        case 1 :
            return selectionWidget;
            break;
966

967
968
969
        case 2 :
            return dataWidget;
            break;
970

971
972
        default:
            return NULL;
mat's avatar
mat committed
973
    }
974
}
975

976
// -------------------- getIcon -----------