Skip to content

File main_3d_window.hpp

File List > gui > main_3d_window.hpp

Go to the documentation of this file

#pragma once

#include <QMainWindow>
#include <QMetaObject>
#include <QProgressBar>
#include <QTreeWidgetItem>
#include <QWidget>
#include <optional>
#include <unordered_map>

#include "gl_widget.hpp"
#include "gui/layer_renderer.hpp"
#include "utilities/filesystem.hpp"

struct Config;

class QComboBox;
class QDialog;
class QDoubleSpinBox;
class QGroupBox;
class QLabel;
class QPushButton;
class QSlider;

QT_BEGIN_NAMESPACE
namespace Ui {
class Main3DWindow;
}
QT_END_NAMESPACE

class ProgressTrackerBar : public QProgressBar, public ProgressObserver {
  AsyncProgressTracker m_progress_tracker;
  bool m_tracker_obtained = false;

 public:
  explicit ProgressTrackerBar(QWidget* parent) : QProgressBar(parent), m_progress_tracker(this) {
    setMinimum(0);
    setMaximum(1000);
  }

  virtual void update_progress(double progress) override {
    const int value = static_cast<int>(progress * 1000.0);
    const bool finished = progress >= 0.999;
    QMetaObject::invokeMethod(
        this,
        [this, value, finished]() {
          setValue(value);
          if (finished) {
            hide();
          }
        },
        Qt::QueuedConnection);
  }

  virtual void text_update(const std::string& text, int depth = 0) override {
    (void)text;
    (void)depth;
  }

  AsyncProgressTracker tracker() {
    Assert(!m_tracker_obtained);
    m_tracker_obtained = true;
    return m_progress_tracker;
  }
};

class Main3DWindow : public QMainWindow {
  Q_OBJECT

 public:
  Main3DWindow();
  ~Main3DWindow() override;

  void add_layer(std::unique_ptr<Layer> layer, bool auto_zoom = true);

  void import_blaze_output_from_path(const std::string& directory);
  void set_exit_after_load(bool exit_after_load);
  void set_exit_after_render(bool exit_after_render) { m_exit_after_render = exit_after_render; }
  void set_bench_mode(bool bench) { m_bench_mode = bench; }
  void set_defer_render_until_loaded(bool defer);

  AsyncProgressTracker add_progress_tracker();
  const std::string& scene_reference_crs() const { return gl_widget->reference_crs_wkt(); }

 private slots:
  void open_layer_file();
  void import_blaze_output();
  void open_lighting_settings();
  void run_blaze_on_layers();
  void on_treeWidget_itemChanged(QTreeWidgetItem* item, int column);
  void on_treeWidget_customContextMenuRequested(const QPoint& pos);
  void remove_selected_layer();
  void maybe_exit_after_load();
  void finish_exit_after_load();

 private:
  void add_layer_to_tree(std::shared_ptr<Layer> layer);
  void remove_layer(const std::shared_ptr<Layer>& layer);
  QTreeWidgetItem* find_tree_item_for_layer(Layer* layer) const;
  void update_render_mode();
  void run_blaze_with_config(const Config& config, QDialog* config_dialog);

  static bool layer_is_ready(const Layer& layer);

  std::unique_ptr<Ui::Main3DWindow> ui;
  std::unique_ptr<GLWidget> gl_widget;
  std::vector<std::shared_ptr<Layer>> m_layers;
  // Progress bar owned per layer. Keyed by Layer* so removal never depends on
  // the bar vector staying index-parallel with m_layers. The pending bar is
  // created by add_progress_tracker() before the layer exists, then claimed by
  // the next add_layer().
  std::unordered_map<const Layer*, ProgressTrackerBar*> m_layer_progress_bars;
  ProgressTrackerBar* m_pending_progress_bar = nullptr;
  bool m_exit_after_load = false;
  bool m_exit_after_render = false;
  bool m_exit_after_load_fired = false;
  bool m_bench_mode = false;
  bool m_defer_render_until_loaded = false;

  QWidget* m_point_cloud_panel = nullptr;
  QGroupBox* m_surface_layer_panel = nullptr;
  QSlider* m_surface_opacity_slider = nullptr;
  QLabel* m_surface_opacity_value_label = nullptr;
  QDoubleSpinBox* m_surface_vertical_offset_spin = nullptr;
  QSlider* m_point_size_slider = nullptr;
  QSlider* m_point_alpha_slider = nullptr;
  QSlider* m_point_stream_budget_slider = nullptr;
  QLabel* m_point_size_value_label = nullptr;
  QLabel* m_point_alpha_value_label = nullptr;
  QLabel* m_point_stream_budget_value_label = nullptr;
  QComboBox* m_point_color_mode_combo = nullptr;
  QPushButton* m_point_fixed_color_button = nullptr;
  QGroupBox* m_point_details_panel = nullptr;
  QLabel* m_point_details_label = nullptr;
  std::weak_ptr<LASLayer> m_active_las_layer;
  std::weak_ptr<Layer> m_active_surface_layer;
  bool m_updating_point_cloud_ui = false;
  bool m_updating_surface_ui = false;
  bool m_zoom_after_load = false;
  bool m_zoom_completed = false;

  void setup_animation_panel();
  void setup_point_cloud_panel();
  void setup_surface_layer_panel();
  void setup_point_details_panel();
  void show_point_pick_details(const PointPickResult& pick);
  void clear_point_pick_details();
  void update_layer_panels_for_selection();
  void update_point_cloud_panel_for_selection();
  void update_surface_layer_panel_for_selection();
  void update_point_cloud_value_labels();
  void update_surface_layer_value_labels();
  void apply_point_cloud_style_from_ui();
  void apply_surface_layer_style_from_ui();
};