.. _multiple-views-page:

##############
Multiple Views
##############

With |ProductName|, you can operate on multiple models and multiple views at the same time. This is a powerful 
feature that enables the user get a better overview of the analysis by, for instance:

- Analyze and compare multiple models at the same time
- Compare different simulation runs/time steps side by side
- View multiple versions of the same model file with different feature extractions or results visualization 
- Look at the same model from different point of views a the same time

The views can have synchronized navigation or operate independently. If you have the same model in multiple views, all 
result visualization and feature extractions will apply to all the views the model is presented in.

.. image:: ../../images/multiple_views.png

To have multiple views, you need one :class:`viewer <cee::vis::Viewer>` per :class:`view <cee::vis::View>`. Read more on
how to setup a viewer on :ref:`toolkits-page`. 

***********************
Creating Multiple Views
***********************

Below is example code on creating multiple views (using the Qt toolkit). This creates two views and puts the same model
in both views. An info box and an axis cross is also added to each view.

.. code-block:: cpp

    MainWindow::MainWindow(cee::vis::OpenGLContextGroup* contextGroup)
    :   m_openGLContextGroup(contextGroup)
    {
        QFrame* mainFrame = new QFrame;
        QGridLayout* frameLayout = new QGridLayout;
        mainFrame->setLayout(frameLayout);
        setCentralWidget(mainFrame);

        std::vector<cee::qt::ViewerOpenGLWidgetDemo*> viewers;
        std::vector<cee::PtrRef<cee::vis::View> > views;

        // Create multiple views
        size_t numViewers = 2;
        for (size_t i = 0; i < numViewers; i++)
        {
            viewers.push_back(new cee::qt::ViewerOpenGLWidgetDemo(contextGroup, mainFrame));
            frameLayout->addWidget(viewers[i], 0, static_cast<int>(i));

            cee::PtrRef<cee::vis::View> view = new cee::vis::View;
            views.push_back(view);
            viewers[i]->setView(view.get());

            view->overlay().addItem(new cee::vis::OverlayAxisCross(&view->camera(),
                cee::vis::Font::createNormalFont().get()),
                cee::vis::OverlayItem::BOTTOM_LEFT, cee::vis::OverlayItem::HORIZONTAL);

            cee::vis::OverlayTextBox* textBox = new cee::vis::OverlayTextBox(cee::vis::Font::createNormalFont().get());
            textBox->setText(cee::qt::UtilsCore::toStr(QString("View %1").arg(i + 1)));
            textBox->setSizeToFitText();
            view->overlay().addItem(textBox, cee::vis::OverlayItem::TOP_LEFT, cee::vis::OverlayItem::HORIZONTAL);
        }

        // Create one model and add it to all views
        cee::PtrRef<cee::geo::GeometryModel> theModel = new cee::geo::GeometryModel;
        views[0]->addModel(theModel.get()); // Model musts be added to a view before parts can be added

        cee::geo::Part* part = new cee::geo::Part(cee::geo::DataGenerator::createBox(cee::Vec3d(0, 0, 0), cee::Vec3d(1, 0.75f, 0.5)).get());
        part->settings().addEffect(new cee::geo::EffectColor(cee::Color3f(0.00f, 0.53f, 0.58f)));
        theModel->addPart(part);

        for (size_t i = 0; i < numViewers; i++)
        {
            if (i > 0) // Model already added to first view
            {
                views[i]->addModel(theModel.get());
            }

            cee::BoundingBox bb = views[i]->boundingBox();
            views[i]->camera().fitView(bb, cee::Vec3d(0, 0, -1), cee::Vec3d(0, 1, 0));
        }
    }

****************************
Synchronizing Multiple Views
****************************

If you want to synchronize the navigation between the views, create functionality to get the current camera setup from
the view you've changed, and apply this to the views you want to synchronize. Then piggy back on the viewers events and
call this function. For instance in mouseMoveEvent() and mouseWheelEvent(). 

.. code-block:: cpp

    void MainWindow::updateNavigationInSyncedViews(cee::vis::View* masterView)
    {
        const cee::vis::Camera& masterCamera = masterView->camera();
        cee::Vec3d eye, vrp, up;
        masterCamera.toLookAt(&eye, &vrp, &up);

        cee::vis::Camera::ProjectionType projection = masterCamera.projection();
        const double frustumHeight = masterCamera.frontPlaneFrustumHeight();
        const double nearPlane = masterCamera.nearPlane();
        const double farPlane = masterCamera.farPlane();
        const double pi = 3.14159265358979323846;

        for (size_t i = 0; i < views.size(); i++)
        {
            if (masterView == views[i])
            {
                continue;
            }

            views[i]->camera().setFromLookAt(eye, vrp, up);

            if (projection == cee::vis::Camera::PERSPECTIVE)
            {
                double fovY = 2 * atan((frustumHeight / 2) / nearPlane);
                if (fovY > 0)
                {
                    views[i]->camera().setProjectionAsPerspective(fovY * 180.0 / pi, nearPlane, farPlane);
                }
            }
            else if (projection == cee::vis::Camera::ORTHO)
            {
                if (frustumHeight > 0)
                {
                    views[i]->camera().setProjectionAsOrtho(frustumHeight, nearPlane, farPlane);
                }
            }
            views[i]->requestRedraw();
        }
    }

.. code-block:: cpp

    void ViewerOpenGLWidgetDemo::mouseMoveEvent(QMouseEvent* event)
    {

        ...

        MainWindow::instance()->updateNavigationInSyncedViews(view());
    }


.. image:: ../../images/multiple_views_example.png


*******
Example
*******

**QtMultiView**

.. |img_multi| image:: ../../images/example_qt_multiview.png
   :width: 150

+-----------------------+------------------------------------------------------------------------------------+
| |img_multi|           | **Location**\ : Examples/Qt/QtMultiView |br|                                       |
|                       | There's a small Qt example showing multiple views included in the   |br|           |
|                       | |ProductName| distribution.                                                        |
+-----------------------+------------------------------------------------------------------------------------+

