# Multiple Views

With HOOPS Envision for Desktop, 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.

To have multiple views, you need one `viewer` per `view`. Read more on how to setup a viewer on UI Toolkit Integrations.

## 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.

    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().

    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();
        }
    }

    void ViewerOpenGLWidgetDemo::mouseMoveEvent(QMouseEvent* event)
    {

        ...

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

## Example

QtMultiView

| Location: Examples/Qt/QtMultiView There’s a small Qt example showing multiple views included in the HOOPS Envision for Desktop distribution.

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Envision for Desktop in your own language, or choose a sample question below to start a conversation:

What is HOOPS Envision for Desktop?
What are the latest release notes for HOOPS Envision for Desktop?
How do I start evaluating HOOPS Envision for Desktop?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...