InteractiveViewer.cpp 98.2 KB
Newer Older
1
/*****************************************************************************
2 3 4
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
5
 * (c) 2001-2018 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

// -- Core stuff
Jean-Loup HABERBUSCH's avatar
Jean-Loup HABERBUSCH committed
27
#include "Action.h"
28
#include "RendererWidget.h"
29
#include "InteractiveViewer.h"
30
#include "SliderSpinBoxWidget.h"
31
#include "Log.h"
32
#include "MeshComponent.h"
33
#include "MeshDataModel.h"
34
#include "PropertyObject.h"
35 36 37 38 39 40 41 42 43 44 45

// -- stl stuff

// -- Qt stuff
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QFileDialog>
#include <QWhatsThis>
#include <QColorDialog>
#include <QToolBar>
#include <QSettings>
46
#include <QWidgetAction>
47
#include <QTextStream>
48
#include <QSplitter>
49 50 51 52 53 54 55 56 57

// -- vtk stuff
#include <vtkDataSetMapper.h>
#include <vtkImageActor.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkTransform.h>
#include <vtkFloatArray.h>
58
#include <vtkIdTypeArray.h>
59 60 61 62
#include <vtkVertex.h>
#include <vtkCellData.h>
#include <vtkCallbackCommand.h>
#include <vtkActor2D.h>
63
#include <vtkActor.h>
64 65 66 67
#include <vtkActorCollection.h>
#include <vtkCamera.h>
#include <vtkPointPicker.h>
#include <vtkCellPicker.h>
cfouard's avatar
cfouard committed
68
#include <vtkProp3DCollection.h>
69
#include <vtkEventQtSlotConnect.h>
70 71 72 73 74 75 76 77 78 79
#include <vtkSelectionNode.h>
#include <vtkSelection.h>
#include <vtkAreaPicker.h>
#include <vtkRenderedAreaPicker.h>
#include <vtkHardwareSelector.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRendererCollection.h>
#include <vtkExtractSelectedFrustum.h>
#include <vtkPointData.h>
80
#include <vtkImageProperty.h>
81

82 83
namespace camitk {
// ---------------------- singleton ----------------------------
84
/// the register containing all the viewers (static instantiation, global variable, but global only for this file)
85
QMap<QString, InteractiveViewer*> InteractiveViewer::viewers;
86
QString InteractiveViewer::defaultNames[5] = {QString("3DViewer"), QString("axialViewer"), QString("coronalViewer"), QString("sagittalViewer"), QString("arbitraryViewer") };
87

88 89
InteractiveViewer* InteractiveViewer::getNewViewer(QString name, ViewerType type) {
    if (!viewers.contains(name)) {
90
        //-- Congratulation, you got yourself a new InteractiveViewer! (but are you really sure you need it?)
91
        viewers[name] = new InteractiveViewer(name, type);
92 93
    }

94
    return viewers.value(name);
95 96
}

97
InteractiveViewer* InteractiveViewer::getViewer(QString name) {
98
    const std::string nameChar = name.toStdString();
99

100 101
    if (viewers.contains(name)) {
        return viewers.value(name);
102
    }
103 104
    else {
        //-- if this is a default scene, get a new one if it does not exists
105
        // perform the singleton instantiation here!
106 107 108
        unsigned int i = 0;
        // special case, the first viewer is a 3D viewer

109 110
        if (name == defaultNames[i]) {
            return getNewViewer(defaultNames[i], GEOMETRY_VIEWER);
111
        }
112

113
        InteractiveViewer* singletonInstance = nullptr;
114 115 116

        i++;

117 118 119
        while (i < 6 && !singletonInstance) {
            if (name == defaultNames[i]) {
                singletonInstance = getNewViewer(defaultNames[i], SLICE_VIEWER);
120
            }
121

122 123 124
            i++;
        }

125 126 127
        // default orientation for axial, sagittal and coronal is not the same
        // See Image Reorientation Action Documentation...
//        singletonInstance->toggleOrientationDecorations(false);
128 129 130 131 132
        if (name ==  defaultNames[1]) {   // Axial Viewer
            singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::RIGHT_DOWN);
            QString letters[4] = {QString("R"), QString("L"), QString("A"), QString("P") };
            singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters);
            singletonInstance->toggleOrientationDecorations(true);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
133
            singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn();
134
        }
Emmanuel Promayon's avatar
Emmanuel Promayon committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
        else
            if (name ==  defaultNames[2]) {    // Coronal Viewer
                singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::LEFT_BACK);
                QString letters[4] = {QString("R"), QString("L"), QString("S"), QString("I") };
                singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters);
                singletonInstance->toggleOrientationDecorations(true);
                singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn();
            }
            else
                if (name ==  defaultNames[3]) {    // Sagittal Viewer
                    singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::BACK_DOWN);
                    QString letters[4] = {QString("A"), QString("P"), QString("S"), QString("I") };
                    singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters);
                    singletonInstance->toggleOrientationDecorations(true);
                    singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn();
                }
                else
                    if (name ==  defaultNames[4]) {    // Arbitrary Viewer
153 154 155
			            singletonInstance->getRendererWidget()->setCameraOrientation ( RendererWidget::RIGHT_DOWN );
                        singletonInstance->toggleOrientationDecorations(true);
			            singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn();
Emmanuel Promayon's avatar
Emmanuel Promayon committed
156
                    }
157 158


159 160 161 162
        return singletonInstance;
    }
}

163
InteractiveViewer* InteractiveViewer::get3DViewer() {
164
    return getViewer(defaultNames[0]);
165 166
}

167
InteractiveViewer* InteractiveViewer::getAxialViewer() {
168
    return getViewer(defaultNames[1]);
169 170
}

171
InteractiveViewer* InteractiveViewer::getCoronalViewer() {
172
    return getViewer(defaultNames[2]);
173 174
}

175
InteractiveViewer* InteractiveViewer::getSagittalViewer() {
176
    return getViewer(defaultNames[3]);
177 178
}

179
InteractiveViewer* InteractiveViewer::getArbitraryViewer() {
180
    return getViewer(defaultNames[4]);
181 182 183
}

// ---------------------- constructor ----------------------------
184
InteractiveViewer::InteractiveViewer(QString& name, ViewerType type) : Viewer(name) {
185 186 187

    myType = type;

188
    // frame is NULL, but the rendererWidget and sliceSlider have to be instantiated
189
    // (even if the InteractiveViewer is not visible yet, it can still do some actions)
190
    frame = nullptr;
191 192 193

    //-- create and init the RendererWidget object for display and interactions

194
    if (myType == SLICE_VIEWER) {
195
        // block rotations (interactions)
196 197
        rendererWidget = new RendererWidget(frame, RendererWidget::TRACKBALL_2D);
        sliceSlider = new SliderSpinBoxWidget(frame);
198 199
    }
    else {
200
        // classic 3D view
201
        rendererWidget = new RendererWidget(frame);
202
        sliceSlider = nullptr;
203 204
    }

205
    cameraMap.insert("default", rendererWidget->getActiveCamera());
mat's avatar
mat committed
206

207
    //-- create the slice slider if needed
208
    viewerMenu = nullptr;
Emmanuel Promayon's avatar
Emmanuel Promayon committed
209
    viewerToolbar = nullptr;
210
    screenshotActionMenu = nullptr;
211 212 213 214
    displayedTopLevelComponents = 0;

    //-- set picking mode
    pickingEffectIsSelecting = true; // default effect
215
    isPicking = false; // by default, viewer is not picking
216

Emmanuel Promayon's avatar
Emmanuel Promayon committed
217
    if (myType == SLICE_VIEWER) {
218
        // by default, the 2D scenes are set to pick slice pixels
219
        initPicking(InteractiveViewer::PIXEL_PICKING);
220
    }
Emmanuel Promayon's avatar
Emmanuel Promayon committed
221
    else {
222
        // no picking
223
        initPicking(InteractiveViewer::NO_PICKING);
224
    }
225

226 227
    //-- current interaction is not changing slice
    isChangingSlice = false;
228

229 230
    //-- connection for selection
    connector = vtkSmartPointer<vtkEventQtSlotConnect>::New();
231
    connector->Connect(rendererWidget->GetInteractor(), vtkCommand::EndPickEvent, this, SLOT(picked()));
mat's avatar
mat committed
232

233 234
    // create the different properties of the viewers
    createProperties();
235

236 237 238 239 240 241
    // init from settings
    initSettings();
}

// ---------------------- destructor ----------------------------
InteractiveViewer::~InteractiveViewer() {
242
    viewers.remove(this->getName());
243 244

    delete viewerMenu;
245
    viewerMenu = nullptr;
246

Emmanuel Promayon's avatar
Emmanuel Promayon committed
247 248
    delete viewerToolbar;
    viewerToolbar = nullptr;
249 250

    delete frame;
251
    frame = nullptr;
252 253 254 255
}

// ---------------------- initSettings ----------------------------
void InteractiveViewer::initSettings() {
256
    QSettings& settings = Application::getSettings();
257
    settings.beginGroup(Application::getName() + ".InteractiveViewer." + objectName().simplified().replace(" ", ""));
258 259 260

    // the background color
    QColor bg;
261
    if (myType == GEOMETRY_VIEWER) {
262
        // default is white
263
        bg.setNamedColor(settings.value("backgroundColor", QColor::fromRgbF(1.0, 1.0, 1.0)).toString());
264
        propertyObject->setProperty(backgroundColorProperty->getName().toStdString().c_str(), bg);
265 266
    }
    else {
267
        // default is black
268
        bg.setNamedColor(settings.value("backgroundColor", QColor::fromRgbF(0.0, 0.0, 0.0)).toString());
269
    }
270 271 272 273

    // the gradient background
    bool gradientBackground;

274 275
    if (myType == GEOMETRY_VIEWER) {
        gradientBackground = settings.value("gradientBackground", true).toBool();
276
        propertyObject->setProperty(backgroundGradientColorProperty->getName().toStdString().c_str(), gradientBackground);
277 278
    }
    else {
279
        gradientBackground = settings.value("gradientBackground", false).toBool();
280
    }
281 282 283

    // the control mode
    RendererWidget::ControlMode controlMode;
promayon's avatar
promayon committed
284

285 286
    if (myType == GEOMETRY_VIEWER) {
        controlMode = (RendererWidget::ControlMode) settings.value("controlMode", RendererWidget::TRACKBALL).toInt();
287 288
    }
    else {
289
        controlMode = (RendererWidget::ControlMode) settings.value("controlMode", RendererWidget::TRACKBALL_2D).toInt();
290
    }
promayon's avatar
promayon committed
291

292
    rendererWidget->setControlMode(controlMode);
293 294 295

    // the initial camera orientation
    RendererWidget::CameraOrientation cameraOrientation;
296 297
    cameraOrientation = (RendererWidget::CameraOrientation) settings.value("cameraOrientation", rendererWidget->getCameraOrientation()).toInt();
    rendererWidget->setCameraOrientation(cameraOrientation);
298

299
    // highlight mode
300
    HighlightMode highlightMode = (HighlightMode) settings.value("highlightMode", SELECTION).toInt();
301
    propertyObject->setProperty(highlightModeProperty->getName().toStdString().c_str(), highlightMode);
302

303
    // lines as tubes
304
    bool linesAsTubes = settings.value("linesAsTubes", false).toBool();    // default false
305
    propertyObject->setProperty(linesAsTubesProperty->getName().toStdString().c_str(), linesAsTubes);
306

307
    // screenshot Action visibility
308
    bool screenshotActionVisible = settings.value("screenshotActionVisible", false).toBool();
309
    propertyObject->setProperty(screenshotActionProperty->getName().toStdString().c_str(), screenshotActionVisible);
310

311
    // backface culling
312
    bool backfaceCulling = settings.value("backfaceCulling", false).toBool();    // default false
313
    propertyObject->setProperty(backfaceCullingProperty->getName().toStdString().c_str(), backfaceCulling);
314

315
    // point size
316
    double pointSize = settings.value("pointSize", 4.0).toDouble();
317
    propertyObject->setProperty(pointSizeProperty->getName().toStdString().c_str(), pointSize);
318

319
    // orientation letters
320 321
    if (myType == GEOMETRY_VIEWER) {
        rendererWidget->toggleOrientationDecorations(false);
322
    }
323 324

    settings.endGroup();
325 326 327 328 329 330 331 332 333 334 335 336

    // -- propertyObject event filter delegation
    // This method changes the properties, which will automatically trigger the
    // QEvent::DynamicPropertyChange
    // This in turns will call eventFilter each time
    // As the settings group is opened, it will generate nested beginGroup
    // Therefore the event filter should only be installed at the end,
    // when all properties are set.

    // propertyObject is monitored by the 3D viewer instance (this) when its properties change
    // All event filter on the property object are delegated to the InteractiveViewer class
    // @see eventFilter()
337
    if (myType == GEOMETRY_VIEWER) {
338 339
        propertyObject->installEventFilter(this);
        // trigger change for all the values
340
        eventFilter(this, new QEvent(QEvent::DynamicPropertyChange));
341 342 343
    }


344 345
}

mat's avatar
mat committed
346
// ---------------------- getWidget ----------------------------
347 348
QWidget* InteractiveViewer::getWidget(QWidget* parent) {
    if (!frame) {
349 350 351 352 353

        //-- create the actions
        initActions();

        //-- build the frame
354 355
        frame = new InteractiveViewerFrame(parent, this);
        frame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
356 357

        //-- handle layout
358 359
        auto* myLayout = new QHBoxLayout(frame);
        auto* horizontalSplitter = new QSplitter(frame);
360 361 362
        myLayout->addWidget(horizontalSplitter);
        myLayout->setSpacing(0);
        myLayout->setMargin(0);
363

364
        //-- show the renderer!
365
        rendererWidget->setParent(frame);
366
        rendererWidget->show();
367
        horizontalSplitter->addWidget(rendererWidget);
368

369
        connect(rendererWidget, SIGNAL(rightButtonPressed()), this, SLOT(rightClick()));
370 371

        //-- create the slider if needed
372
        if (myType == SLICE_VIEWER) {
373
            auto* rightSideLayout = new QVBoxLayout;
374 375
            rightSideLayout->setSpacing(0);
            rightSideLayout->setMargin(0);
376

377
            // add snapshot widget
378 379 380 381 382 383
            screenshotActionMenu = new QToolBar(rendererWidget);
            screenshotActionMenu->addAction(screenshotAction);
            screenshotActionMenu->setEnabled(true);
            screenshotActionMenu->setVisible(false);
            screenshotActionMenu->layout()->setSpacing(0);
            screenshotActionMenu->layout()->setMargin(0);
384

385
            rightSideLayout->addWidget(screenshotActionMenu, 0, Qt::AlignCenter);
386

387
            // add slider
388
            sliceSlider->setParent(frame);
389

390
            // connect the slider to this scene
391 392
            connect(sliceSlider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int)));
            rightSideLayout->addWidget(sliceSlider);
393
            // add the right side layout
394 395 396 397
            sideFrame = new QFrame;
            /*sideFrame->setSpacing ( 0 );
            sideFrame->setMargin ( 0 );
            */
398
            sideFrame->setLayout(rightSideLayout);
399 400 401 402 403 404 405
            QSizePolicy sideFrameSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
            sideFrame->setSizePolicy(sideFrameSizePolicy);
            sideFrame->setMinimumWidth(15);
            sideFrame->setMaximumWidth(60);

            //myLayout->addWidget ( sideFrame );
            horizontalSplitter->addWidget(sideFrame);
406
        }
407
        else {
408
            sideFrame = nullptr;
409
        }
promayon's avatar
promayon committed
410

411
        // do this for receiving key-events
412
        frame->setFocusPolicy(Qt::ClickFocus);
413

414 415
        // TODO A feature disappeared when switching to vtk5...
        // use a vtkOutlineSource to highlight the picked actor (show-hide picked actor bounding box</td>
416 417 418 419
        // set the what's this text
        initWhatsThis();


420 421 422 423 424 425
        startWhatsThisSection("Mouse bindings");
        addWhatsThisItem("Left", "Rotate");
        addWhatsThisItem("Ctrl+Left", "Pick (flip selection flag for point/cell)");
        addWhatsThisItem("Shift+Left", "Translate selection");
        addWhatsThisItem("Middle", "Pan");
        addWhatsThisItem("Right", "Zoom");
426
        endWhatsThisSection();
427 428 429 430 431 432 433 434 435 436 437
        startWhatsThisSection("Keyboard bindings (upper or lower case)");
        addWhatsThisItem("3", "Toggle 3D red/blue stereo display");
        addWhatsThisItem("A", "Toggle view axes");
        addWhatsThisItem("C", "Toggle color scale");
        addWhatsThisItem("F", "Toggle backface culling");
        addWhatsThisItem("I", "Toggle image interpolation on slices");
        addWhatsThisItem("J", "Joystick interaction mode");
        addWhatsThisItem("L", "Toggle view labels");
        addWhatsThisItem("Alt+L", "Toggle light follows camera");
        addWhatsThisItem("Alt+P", "Toggle point rendering");
        addWhatsThisItem("P", "Pick (flip selection flag for point/cell)");
438
        addWhatsThisItem("R", "Reset Image Interactor Look Up Table");
439 440 441 442
        addWhatsThisItem("S", "Take a screenshot");
        addWhatsThisItem("Alt+S", "Toggle surfacerendering");
        addWhatsThisItem("T", "Trackball interaction mode");
        addWhatsThisItem("Alt+W", "Toggle wireframe rendering");
443 444 445 446
        endWhatsThisSection();


        startWhatsThisSection();
447 448 449 450 451 452 453 454 455 456 457
        addWhatsThisItem("SPACE", "Update/refresh view");
        addWhatsThisItem("HOME", "Reset camera to default view point or so that everything is visible");
        addWhatsThisItem("LEFT", "Turn -5&deg; around camera Y axis");
        addWhatsThisItem("Ctrl+LEFT", "Turn -90&deg; around camera Y axis");
        addWhatsThisItem("RIGHT", "Turn 5&deg; around camera Y axis");
        addWhatsThisItem("Ctrl+RIGHT", "Turn 90&deg; around camera Y axis");
        addWhatsThisItem("UP", "Turn -5&deg; around camera X axis");
        addWhatsThisItem("Ctrl+UP", "Turn -90&deg; around camera X axis");
        addWhatsThisItem("DOWN", "Turn 5&deg; around camera X axis");
        addWhatsThisItem("Ctrl+DOWN", "Turn 90&deg; around camera X axis");
        addWhatsThisItem("+", "Move slider a step above");
458
        addWhatsThisItem("-", "Move slider a step below");
459 460 461
        addWhatsThisItem("PAGE Up", "Move slider a page above");
        addWhatsThisItem("PAGE Down", "Move slider a page down");
        addWhatsThisItem("ESC", "Clear current selection");
462 463 464
        endWhatsThisSection();


465 466 467
        startWhatsThisSection("Other Shortcuts");
        addWhatsThisItem("F1", "Show this help (i.e. the what's this help)");
        addWhatsThisItem("F2", "Print debugging information on console");
468 469 470
        endWhatsThisSection();

        // add the text as whatsThis
471
        frame->setWhatsThis(whatsThis);
472 473
    }
    else {
474
        if (frame->parentWidget() != parent) {
475
            bool isVisible = frame->isVisible();
476 477
            frame->setParent(parent);
            frame->setVisible(isVisible);
478
        }
promayon's avatar
promayon committed
479
    }
480 481 482 483 484

    return frame;
}

// ---------------------- getPropertyObject ----------------------------
485
QObject* InteractiveViewer::getPropertyObject() {
486
    if (myType == GEOMETRY_VIEWER) {
487
        return propertyObject;
488 489
    }
    else {
490
        return nullptr;
491
    }
492 493 494 495 496 497 498 499 500 501 502 503 504
}

// ---------------------- getName ----------------------------
QString InteractiveViewer::getName() const {
    return objectName();
}

// ---------------- numberOfViewedComponent ----------------
unsigned int InteractiveViewer::numberOfViewedComponent() {
    return actorMap.size();
}

// ---------------------- refresh ----------------------------
505
void InteractiveViewer::refresh(Viewer* v) {
mat's avatar
mat committed
506

507
    //-- do not refresh if the widget was not created
508
    if (!frame) {
509
        return;
510
    }
511

512
    //-- first remove non active Component (if InteractiveViewer was called by itself, no need to do that)
513
    if (v != this) {
514 515
        //-- check all present
        QList<Component*> compRendered = actorMap.keys();
516 517
        foreach (Component* comp, compRendered) {
            if (!Application::isAlive(comp)) {
518
                // remove from the renderer and map
519
                removeAllActors(comp);
520 521 522 523 524
            }
        }
    }

    //-- now check the full component list
525
    ComponentList allComponents = Application::getAllComponents();
526

527
    switch (myType) {
528 529
        case GEOMETRY_VIEWER:
            // check all Components
530
            foreach (Component* comp, allComponents) {
531
                // remove from the renderer and map
532
                removeAllActors(comp);
533

534
                // check if the Component is to be displayed here
535 536
                if (comp->getVisibility(this)) {
                    if (comp->getRepresentation() == Component::GEOMETRY) {
537
                        //-- set the correct rendering parameters
538
                        updateSelectionDisplay(comp);
539 540 541

                        //-- check the line as tube representation
                        bool linesAsTubes = propertyObject->property(linesAsTubesProperty->getName().toStdString().c_str()).toBool();
542 543
                        if (linesAsTubes) {
                            comp->setLinesAsTubes(linesAsTubes);
544
                        }
545

546
                        //-- add the correct actors (NULL is return if the actor is not appropriate, i.e. hidden or not in proper mode)
547 548 549
                        addActor(comp, comp->getActor(InterfaceGeometry::Surface));
                        addActor(comp, comp->getActor(InterfaceGeometry::Wireframe));
                        addActor(comp, comp->getActor(InterfaceGeometry::Points));
550

551 552
                        for (unsigned int i = 0; i < comp->getNumberOfProp(); i++) {
                            addActor(comp, comp->getProp(i));
553
                        }
promayon's avatar
promayon committed
554
                    }
555
                    else {
556 557
                        if (comp->getRepresentation() == Component::SLICE) {
                            addActor(comp, comp->get3DImageActor());
558

559 560
                            for (unsigned int i = 0; i < comp->getNumberOfProp(); i++) {
                                addActor(comp, comp->getProp(i));
561 562 563 564
                            }
                        }
                    }
                }
565 566
                if (comp->getFrameVisibility(this)) {
                    addActor(comp, comp->getFrameAxisActor());
567
                }
568

569 570
            }

571
            break;
572

573 574 575
        case SLICE_VIEWER:
            // remove all from the renderer and map
            QList<Component*> compRendered = actorMap.keys();
576 577
            foreach (Component* comp, compRendered) {
                removeAllActors(comp);
578
            }
579

580 581
            // only display the last selected (if exists otherwise the last added)
            int idOfLastSelected = Application::getSelectedComponents().size() - 1;
582

583 584
            if (idOfLastSelected >= 0) {
                while (idOfLastSelected >= 0 && !(Application::getSelectedComponents() [idOfLastSelected]->getVisibility(this) && Application::getSelectedComponents() [idOfLastSelected]->getRepresentation() == Component::SLICE)) {
585 586
                    idOfLastSelected--;
                }
587 588
            }

589
            if (idOfLastSelected >= 0) {
590 591

                // there is valid Component to display
592
                Component* comp = Application::getSelectedComponents() [idOfLastSelected];
593
                // add both the slices, the plane used for picking and the pixel highlighter
594 595 596
                addActor(comp, comp->getPixelActor());
                addActor(comp, comp->get2DImageActor());
                addActor(comp, comp->getPickPlaneActor());
597

598 599
                for (unsigned int i = 0; i < comp->getNumberOfProp(); i++) {
                    addActor(comp, comp->getProp(i));
600
                }
601

602
                // set the slider range and update widgets values
603 604
                sliceSlider->setRange(0, comp->getNumberOfSlices() - 1);
                sliceSlider->setValue(comp->getSlice());
605
            }
606
            else {
promayon's avatar
promayon committed
607

608 609 610
                // no selection, get the last added Component
                idOfLastSelected = allComponents.size() - 1;

611
                while (idOfLastSelected >= 0 && !(allComponents[idOfLastSelected]->getVisibility(this) && allComponents[idOfLastSelected]->getRepresentation() == Component::SLICE)) {
612 613 614
                    idOfLastSelected--;
                }

615
                if (idOfLastSelected >= 0) {
616 617 618 619

                    // there is valid Component to display
                    Component* comp = allComponents[idOfLastSelected];
                    // add both the slices, the plane used for picking and the pixel highlighter
620 621 622
                    addActor(comp, comp->getPixelActor());
                    addActor(comp, comp->get2DImageActor());
                    addActor(comp, comp->getPickPlaneActor());
623

624 625
                    for (unsigned int i = 0; i < comp->getNumberOfProp(); i++) {
                        addActor(comp, comp->getProp(i));
626 627 628
                    }

                    // set the slider range and update widgets values
629 630
                    sliceSlider->setRange(0, comp->getNumberOfSlices() - 1);
                    sliceSlider->setValue(comp->getSlice());
631 632 633 634
                }
            }

            break;
635 636
    }

637
    // refresh only camera on slice viewer which are not being picked nor is changing slice or geometry viewer which needs additional refresh
638
    if (displayedTopLevelComponents == (unsigned) Application::getTopLevelComponents().size()) {
639
        rendererWidget->updateAxes();
640

641
        // refresh only camera on slice viewer which are not being picked or geometry viewer which needs additional refresh
642
        if (((myType == SLICE_VIEWER) && !isPicking)) {
643
            if (!isChangingSlice) {
644
                resetCamera();
645
            }
646 647
            else
                // just reset clipping range
648
            {
649
                rendererWidget->resetClippingPlanes();
650
            }
651 652
            // TODO add a boolean "Reset camera when picking" that can be set on or off
            // and saved as a setting
653
        }
mat's avatar
mat committed
654
        rendererWidget->refresh();
655 656
    }
    else {
mat's avatar
mat committed
657
        // there is some difference => reset camera in case of Geometry Viewer
658
        rendererWidget->updateAxes();
mat's avatar
mat committed
659
        resetCamera();
660
        displayedTopLevelComponents = Application::getTopLevelComponents().size();
661 662 663 664 665 666 667 668 669 670 671 672
    }

    //-- update actions
    updateActions();
}

// ---------------------- refreshRenderer ----------------------------
void InteractiveViewer::refreshRenderer() {
    rendererWidget->refresh();
}

// ---------------------- removeAllActors ----------------------------
673 674 675 676
void InteractiveViewer::removeAllActors(Component* comp) {
    QList<vtkSmartPointer<vtkProp> > actorRendered = actorMap.values(comp);
    foreach (vtkSmartPointer<vtkProp> a, actorRendered) {
        rendererWidget->removeProp(a);
677 678
    }
    // remove from the list
679
    actorMap.remove(comp);
680 681 682
}

// ---------------------- addActor ----------------------------
683 684 685 686
void InteractiveViewer::addActor(Component* comp, vtkSmartPointer<vtkProp> a) {
    if (a) {
        rendererWidget->addProp(a);
        actorMap.insert(comp, a);
687 688 689 690
    }
}

// ---------------------- getMenu ----------------------------
691
QMenu* InteractiveViewer::getMenu() {
692
    if (frame && !viewerMenu) {
693
        //-- create the main menu
694 695
        viewerMenu = new QMenu(objectName());
        viewerMenu->setTearOffEnabled(true);
696 697

        //-- add actions to the menu
698 699 700 701 702 703 704
        QMenu* options = new QMenu("View Options");
        options->addAction(backgroundColorAction);
        options->addAction(toggleCopyrightAction);
        options->addAction(toggleAxesAction);
        if (myType == SLICE_VIEWER) {
            options->addAction(toggleOrientationDecorationsAction);
            options->addAction(toggleScreenshotAction);
705
        }
706

707
        // AxesView mode
708 709 710 711 712
        QMenu* cameraOrientationMenu = new QMenu("Camera Orientation");
        options->addMenu(cameraOrientationMenu);
        cameraOrientationMenu->addAction(cameraOrientationRightDownAction);
        cameraOrientationMenu->addAction(cameraOrientationLeftUpAction);
        cameraOrientationMenu->addAction(cameraOrientationRightUpAction);
713

714
        if (myType == GEOMETRY_VIEWER) {
715 716
            options->addSeparator();
            //options->addAction(toggleAxesAction);
717 718 719
            options->addAction(toggleLabelAction);
            options->addAction(toggleLinesAsTubesAction);
            options->addAction(toggleBackfaceCullingAction);
720 721

            // display mode
722 723 724 725 726
            QMenu* highlightMenu = new QMenu("Highlight Mode");
            options->addMenu(highlightMenu);
            highlightMenu->addAction(highlightOffAction);
            highlightMenu->addAction(highlightSelectionAction);
            highlightMenu->addAction(highlightSelectionOnlyAction);
727 728

            // camera menu
729 730 731 732
            QMenu* controlModeMenu = new QMenu("Camera Control");
            controlModeMenu->addAction(controlModeTrackballAction);
            controlModeMenu->addAction(controlModeJoystickAction);
            options->addMenu(controlModeMenu);
733 734 735

            // force toolbar creation and add it
            options->addSeparator();
736
            options->addAction(getToolBar()->toggleViewAction());
737 738
        }

739
        viewerMenu->addMenu(options);
740

741
        if (myType == GEOMETRY_VIEWER) {
742 743
            viewerMenu->addSeparator();
            // picking menu
744 745 746 747
            QMenu* pickingMenu = new QMenu("&Picking");
            pickingMenu->addAction(pickPointAction);
            pickingMenu->addAction(pickCellAction);
            viewerMenu->addMenu(pickingMenu);
748

749
            viewerMenu->addMenu(renderingMenu);
750 751
        }

752
        viewerMenu->addAction(screenshotAction);
753 754 755 756 757 758 759 760 761

        //-- update actions
        updateActions();
    }

    return viewerMenu;
}

// ---------------------- getToolBar ----------------------------
762
QToolBar* InteractiveViewer::getToolBar() {
Emmanuel Promayon's avatar
Emmanuel Promayon committed
763
    if (frame && !viewerToolbar) {
Emmanuel Promayon's avatar
Emmanuel Promayon committed
764
        if (myType == GEOMETRY_VIEWER) {
Emmanuel Promayon's avatar
Emmanuel Promayon committed
765
            viewerToolbar = new QToolBar(objectName() + " Toolbar");
Emmanuel Promayon's avatar
Emmanuel Promayon committed
766
            // ensure object name is set for saving the state
Emmanuel Promayon's avatar
Emmanuel Promayon committed
767
            viewerToolbar->setObjectName(objectName() + " Toolbar");
Emmanuel Promayon's avatar
Emmanuel Promayon committed
768

Emmanuel Promayon's avatar
Emmanuel Promayon committed
769 770 771 772
            viewerToolbar->addAction(pickPointAction);
            viewerToolbar->addAction(pickCellAction);
            viewerToolbar->addAction(pickPointRegionAction);
            viewerToolbar->addAction(pickCellRegionAction);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
773

Emmanuel Promayon's avatar
Emmanuel Promayon committed
774
            viewerToolbar->addSeparator();
Emmanuel Promayon's avatar
Emmanuel Promayon committed
775

Emmanuel Promayon's avatar
Emmanuel Promayon committed
776 777 778
            viewerToolbar->addAction(surfaceAction);
            viewerToolbar->addAction(wireframeAction);
            viewerToolbar->addAction(pointsAction);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
779
            if (colorAction) {
Emmanuel Promayon's avatar
Emmanuel Promayon committed
780
                viewerToolbar->addAction(colorAction);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
781
            }
Emmanuel Promayon's avatar
Emmanuel Promayon committed
782 783
            viewerToolbar->addAction(glyphAction);
            viewerToolbar->addAction(toggleLabelAction);
784

Emmanuel Promayon's avatar
Emmanuel Promayon committed
785
            viewerToolbar->addSeparator();
786

Emmanuel Promayon's avatar
Emmanuel Promayon committed
787 788
            viewerToolbar->addAction(toggleAxesAction);
            viewerToolbar->addAction(screenshotAction);
789

Emmanuel Promayon's avatar
Emmanuel Promayon committed
790
            viewerToolbar->addSeparator();
791

Emmanuel Promayon's avatar
Emmanuel Promayon committed
792
            viewerToolbar->addAction(scalarDataColorAction);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
793 794
        }
        /* if (myType == SLICE_VIEWER) {
795
            viewerToolBar->addAction(toggleOrientationDecorationsAction);
796
        }
Emmanuel Promayon's avatar
Emmanuel Promayon committed