ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvPickingHub.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ecvPickingHub.h"
9 
10 // CV_DB_LIB
11 #include <ecvDisplayTools.h>
12 
13 // Qt
14 #include <QMdiSubWindow>
15 
16 // Plugins
17 #include <ecvMainAppInterface.h>
18 
19 ccPickingHub::ccPickingHub(ecvMainAppInterface* app, QObject* parent /*=0*/)
20  : QObject(parent),
21  m_app(app),
22  m_activeWindow(nullptr),
23  m_pickingMode(ecvDisplayTools::POINT_OR_TRIANGLE_PICKING),
24  m_autoEnableOnActivatedWindow(true),
25  m_exclusive(false) {}
26 
28  // CVLog::Warning(QString("Toggle picking mode: ") + (state ? "ON" : "OFF")
29  // + " --> " + (m_activeGLWindow ? QString("View ") +
30  // QString::number(m_activeGLWindow->getUniqueID()) : QString("no view")));
31  if (m_activeWindow) {
34  }
35 }
36 
37 void ccPickingHub::onActiveWindowChanged(QMdiSubWindow* mdiSubWindow) {
38  QWidget* window = (mdiSubWindow ? mdiSubWindow->widget() : nullptr);
39  // if (glWindow)
40  // CVLog::Warning("New active GL window: " + glWindow->getViewId());
41  // else
42  // CVLog::Warning("No more active GL window");
43 
44  if (m_activeWindow == window) {
45  // nothing to do
46  return;
47  }
48 
49  if (m_activeWindow) {
50  // take care of the previously linked window
51  togglePickingMode(false);
52  disconnect(m_activeWindow);
53  m_activeWindow = nullptr;
54  }
55 
56  if (window) {
57  // link this new window
59  this, &ccPickingHub::processPickedItem, Qt::UniqueConnection);
60  connect(ecvDisplayTools::TheInstance(), &QObject::destroyed, this,
62  m_activeWindow = window;
63 
65  togglePickingMode(true);
66  }
67  }
68 }
69 
71  if (obj == m_activeWindow) {
72  m_activeWindow = nullptr;
73  }
74 }
75 
77  unsigned itemIndex,
78  int x,
79  int y,
80  const CCVector3& P3D) {
81  if (m_listeners.empty()) {
82  return;
83  }
84 
86  {
87  item.clickPoint = QPoint(x, y);
88  item.entity = entity;
89  item.itemIndex = itemIndex;
90  item.P3D = P3D;
91  }
92 
93  // copy the list of listeners, in case the user call 'removeListener' in
94  // 'onItemPicked'
95  std::set<ccPickingListener*> listeners = m_listeners;
96 
97  for (ccPickingListener* l : listeners) {
98  if (l) {
99  l->onItemPicked(item);
100  }
101  }
102 }
103 
105  ccPickingListener* listener,
106  bool exclusive /*=false*/,
107  bool autoStartPicking /*=true*/,
108  ecvDisplayTools::PICKING_MODE mode /*=POINT_OR_TRIANGLE_PICKING*/) {
109  if (!listener) {
110  assert(false);
111  return false;
112  }
113 
114  // if listeners are already registered
115  if (!m_listeners.empty()) {
116  if (m_exclusive) // a previous listener is exclusive
117  {
118  assert(m_listeners.size() == 1);
119  if (m_listeners.find(listener) == m_listeners.end()) {
121  "[ccPickingHub::addListener] Exclusive listener "
122  "already registered: stop the other tool relying on "
123  "point picking first");
124  return false;
125  }
126  } else if (exclusive) // this new listener is exclusive
127  {
128  if (m_listeners.size() > 1 ||
129  m_listeners.find(listener) == m_listeners.end()) {
131  "[ccPickingHub::addListener] Attempt to register an "
132  "exclusive listener while other listeners are already "
133  "registered");
134  return false;
135  }
136  } else if (mode != m_pickingMode) {
137  if (m_listeners.size() > 1 ||
138  m_listeners.find(listener) == m_listeners.end()) {
140  "[ccPickingHub::addListener] Other listeners are "
141  "already registered with a different picking mode");
142  return false;
143  }
144  }
145  }
146 
147  try {
148  m_listeners.insert(listener);
149  } catch (const std::bad_alloc&) {
150  // not enough memory
151  CVLog::Warning("[ccPickingHub::addListener] Not enough memory");
152  return false;
153  }
154 
155  m_exclusive = exclusive;
156  m_pickingMode = mode;
157 
158  if (autoStartPicking) {
159  togglePickingMode(true);
160  }
161 
162  return true;
163 }
164 
166  bool autoStopPickingIfLast /*=true*/) {
167  m_listeners.erase(listener);
168 
169  if (m_listeners.empty()) {
170  m_exclusive = false; // auto drop the 'exclusive' flag
171  togglePickingMode(false);
172  }
173 }
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
void processPickedItem(ccHObject *, unsigned, int, int, const CCVector3 &)
std::set< ccPickingListener * > m_listeners
Listeners.
Definition: ecvPickingHub.h:88
bool m_exclusive
Exclusive mode.
void togglePickingMode(bool state)
Manual start / stop of the picking mode on the active window.
bool m_autoEnableOnActivatedWindow
Automatically enables the picking mechanism on activated GL windows.
ccPickingHub(ecvMainAppInterface *app, QObject *parent=nullptr)
Default constructor.
void removeListener(ccPickingListener *listener, bool autoStopPickingIfLast=true)
Removes a listener.
ecvDisplayTools::PICKING_MODE m_pickingMode
Default picking mode.
Definition: ecvPickingHub.h:97
void onActiveWindowDeleted(QObject *)
bool addListener(ccPickingListener *listener, bool exclusive=false, bool autoStartPicking=true, ecvDisplayTools::PICKING_MODE mode=ecvDisplayTools::POINT_OR_TRIANGLE_PICKING)
Adds a listener.
QWidget * m_activeWindow
Active window.
Definition: ecvPickingHub.h:94
void onActiveWindowChanged(QMdiSubWindow *)
Point/triangle picking listener interface.
PICKING_MODE
Picking mode.
static ecvDisplayTools * TheInstance()
void itemPicked(ccHObject *entity, unsigned subEntityID, int x, int y, const CCVector3 &P)
Signal emitted when a point (or a triangle) is picked.
static void SetPickingMode(PICKING_MODE mode=DEFAULT_PICKING)
Main application interface (for plugins)