File: MultipleWindows.cpp

package info (click to toggle)
open3d 0.19.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 83,496 kB
  • sloc: cpp: 206,543; python: 27,254; ansic: 8,356; javascript: 1,883; sh: 1,527; makefile: 259; xml: 69
file content (161 lines) | stat: -rw-r--r-- 6,252 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// ----------------------------------------------------------------------------
// -                        Open3D: www.open3d.org                            -
// ----------------------------------------------------------------------------
// Copyright (c) 2018-2024 www.open3d.org
// SPDX-License-Identifier: MIT
// ----------------------------------------------------------------------------

#include <atomic>
#include <chrono>
#include <mutex>
#include <thread>

#include "open3d/Open3D.h"

using namespace open3d;
using namespace open3d::visualization;

const int WIDTH = 1024;
const int HEIGHT = 768;
const Eigen::Vector3f CENTER_OFFSET(0.0f, 0.0f, -3.0f);
const std::string CLOUD_NAME = "points";

class MultipleWindowsApp {
public:
    MultipleWindowsApp() {
        is_done_ = false;

        gui::Application::GetInstance().Initialize();
    }

    void Run() {
        main_vis_ = std::make_shared<visualizer::O3DVisualizer>(
                "Open3D - Multi-Window Demo", WIDTH, HEIGHT);
        main_vis_->AddAction(
                "Take snapshot in new window",
                [this](visualizer::O3DVisualizer &) { this->OnSnapshot(); });
        main_vis_->SetOnClose([this]() { return this->OnMainWindowClosing(); });

        gui::Application::GetInstance().AddWindow(main_vis_);
        auto r = main_vis_->GetOSFrame();
        snapshot_pos_ = gui::Point(r.x, r.y);

        std::thread read_thread([this]() { this->ReadThreadMain(); });
        gui::Application::GetInstance().Run();
        read_thread.join();
    }

private:
    void OnSnapshot() {
        n_snapshots_ += 1;
        snapshot_pos_ = gui::Point(snapshot_pos_.x + 50, snapshot_pos_.y + 50);
        auto title = std::string("Open3D - Multi-Window Demo (Snapshot #") +
                     std::to_string(n_snapshots_) + ")";
        auto new_vis = std::make_shared<visualizer::O3DVisualizer>(title, WIDTH,
                                                                   HEIGHT);

        geometry::AxisAlignedBoundingBox bounds;
        {
            std::lock_guard<std::mutex> lock(cloud_lock_);
            auto mat = rendering::MaterialRecord();
            mat.shader = "defaultUnlit";
            new_vis->AddGeometry(
                    CLOUD_NAME + " #" + std::to_string(n_snapshots_), cloud_,
                    &mat);
            bounds = cloud_->GetAxisAlignedBoundingBox();
        }

        new_vis->ResetCameraToDefault();
        Eigen::Vector3f center = bounds.GetCenter().cast<float>();
        new_vis->SetupCamera(60, center, center + CENTER_OFFSET,
                             {0.0f, -1.0f, 0.0f});
        gui::Application::GetInstance().AddWindow(new_vis);
        auto r = new_vis->GetOSFrame();
        new_vis->SetOSFrame(
                gui::Rect(snapshot_pos_.x, snapshot_pos_.y, r.width, r.height));
    }

    bool OnMainWindowClosing() {
        // Ensure object is free so Filament can clean up without crashing.
        // Also signals to the "reading" thread that it is finished.
        main_vis_.reset();
        return true;  // false would cancel the close
    }

private:
    void ReadThreadMain() {
        // This is NOT the UI thread, need to call PostToMainThread() to
        // update the scene or any part of the UI.

        data::DemoICPPointClouds demo_icp_pointclouds;
        geometry::AxisAlignedBoundingBox bounds;
        Eigen::Vector3d extent;
        {
            std::lock_guard<std::mutex> lock(cloud_lock_);
            cloud_ = std::make_shared<geometry::PointCloud>();
            io::ReadPointCloud(demo_icp_pointclouds.GetPaths(0), *cloud_);
            bounds = cloud_->GetAxisAlignedBoundingBox();
            extent = bounds.GetExtent();
        }

        auto mat = rendering::MaterialRecord();
        mat.shader = "defaultUnlit";

        gui::Application::GetInstance().PostToMainThread(
                main_vis_.get(), [this, bounds, mat]() {
                    std::lock_guard<std::mutex> lock(cloud_lock_);
                    main_vis_->AddGeometry(CLOUD_NAME, cloud_, &mat);
                    main_vis_->ResetCameraToDefault();
                    Eigen::Vector3f center = bounds.GetCenter().cast<float>();
                    main_vis_->SetupCamera(60, center, center + CENTER_OFFSET,
                                           {0.0f, -1.0f, 0.0f});
                });

        Eigen::Vector3d magnitude = 0.005 * extent;
        utility::random::UniformRealGenerator<double> uniform_gen(-0.5, 0.5);

        while (main_vis_) {
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

            // Perturb the cloud with a random walk to simulate an actual read
            {
                std::lock_guard<std::mutex> lock(cloud_lock_);
                for (size_t i = 0; i < cloud_->points_.size(); ++i) {
                    Eigen::Vector3d perturb(magnitude[0] * uniform_gen(),
                                            magnitude[1] * uniform_gen(),
                                            magnitude[2] * uniform_gen());
                    cloud_->points_[i] += perturb;
                }
            }

            if (!main_vis_) {  // might have changed while sleeping
                break;
            }
            gui::Application::GetInstance().PostToMainThread(
                    main_vis_.get(), [this, mat]() {
                        std::lock_guard<std::mutex> lock(cloud_lock_);
                        // Note: if the number of points is less than or equal
                        // to the number of points in the original object that
                        // was added, using Scene::UpdateGeometry() will be
                        // faster. Requires that the point cloud be a
                        // t::PointCloud.
                        main_vis_->RemoveGeometry(CLOUD_NAME);
                        main_vis_->AddGeometry(CLOUD_NAME, cloud_, &mat);
                    });
        }
    }

private:
    std::mutex cloud_lock_;
    std::shared_ptr<geometry::PointCloud> cloud_;

    std::atomic<bool> is_done_;
    std::shared_ptr<visualizer::O3DVisualizer> main_vis_;
    int n_snapshots_ = 0;
    gui::Point snapshot_pos_;
};

int main(int argc, char *argv[]) {
    MultipleWindowsApp().Run();
    return 0;
}