ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
QVTKWidgetCustom.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 "QVTKWidgetCustom.h"
9 
11 #include "VtkUtils/utils.h"
12 #include "VtkUtils/vtkutils.h"
13 
14 // CV_CORE_LIB
15 #include <CVConst.h>
16 #include <CVLog.h>
17 #include <CVTools.h>
18 
19 // VTK
20 #include <vtkAbstractPicker.h>
21 #include <vtkAngleRepresentation2D.h>
22 #include <vtkAxesActor.h>
23 #include <vtkCamera.h>
24 #include <vtkClipPolyData.h>
25 #include <vtkColorTransferFunction.h>
26 #include <vtkConeSource.h>
27 #include <vtkDelaunay2D.h>
28 #include <vtkGenericOpenGLRenderWindow.h>
29 #include <vtkIdFilter.h>
30 #include <vtkImageData.h>
31 #include <vtkLogoRepresentation.h>
32 #include <vtkLogoWidget.h>
33 #include <vtkLookupTable.h>
34 #include <vtkOrientationMarkerWidget.h>
35 #include <vtkPNGReader.h>
36 #include <vtkProperty2D.h>
37 #include <vtkRenderWindow.h>
38 #include <vtkRenderer.h>
39 #include <vtkRendererCollection.h>
40 #include <vtkScalarBarActor.h>
41 #include <vtkScalarBarRepresentation.h>
42 #include <vtkScalarBarWidget.h>
43 #include <vtkTransform.h>
44 #include <vtkVertexGlyphFilter.h>
45 
46 // CV_DB_LIB
47 #include <ecvDisplayTools.h>
48 #include <ecvInteractor.h>
49 #include <ecvPointCloud.h>
50 #include <ecvPolyline.h>
51 
52 // QT
53 #include <QApplication>
54 #include <QCoreApplication>
55 #include <QHBoxLayout>
56 #include <QLayout>
57 #include <QMainWindow>
58 #include <QMessageBox>
59 #include <QMimeData>
60 #include <QPushButton>
61 #include <QSettings>
62 #include <QThread>
63 #include <QTimer>
64 #include <QTouchEvent>
65 #include <QWheelEvent>
66 #include <QWidget>
67 
68 #ifdef USE_VLD
69 #include <vld.h>
70 #endif
71 
72 #include "ScaleBarWidget.h"
73 
74 // macroes
75 #ifndef VTK_CREATE
76 #define VTK_CREATE(TYPE, NAME) \
77  vtkSmartPointer<TYPE> NAME = vtkSmartPointer<TYPE>::New()
78 #endif
79 
80 class VtkWidgetPrivate {
81 public:
82  VtkWidgetPrivate(QVTKWidgetCustom* q);
83  ~VtkWidgetPrivate();
84 
85  void init();
86  void configRenderer(vtkRenderer* renderer);
87  void layoutRenderers();
88 
89  QVTKWidgetCustom* q_ptr;
90  QColor backgroundColor = Qt::black;
91  bool multiViewports = false;
92  vtkRenderer* defaultRenderer = nullptr;
93  vtkSmartPointer<vtkOrientationMarkerWidget> orientationMarkerWidget =
94  nullptr;
95 
96  QList<vtkRenderer*> renderers;
97  QList<vtkProp*> actors;
98  QList<vtkProp*> props;
99 
100  double bounds[6];
101 };
102 
103 VtkWidgetPrivate::VtkWidgetPrivate(QVTKWidgetCustom* q) : q_ptr(q) { init(); }
104 
105 VtkWidgetPrivate::~VtkWidgetPrivate() {}
106 
107 void VtkWidgetPrivate::configRenderer(vtkRenderer* renderer) {
108  if (!renderer) return;
109 
110  double bgclr[3];
111  Utils::vtkColor(backgroundColor, bgclr);
112 
113  renderer->SetBackground(bgclr);
114 }
115 
116 static int columnCount(int count) {
117  int cols = 1;
118  while (true) {
119  if ((cols * cols) >= count) return cols;
120  ++cols;
121  }
122  return cols;
123 }
124 
126  switch (renderers.size()) {
127  case 1:
128  VtkUtils::layoutRenderers<1>(renderers);
129  break;
130 
131  case 2:
132  VtkUtils::layoutRenderers<2>(renderers);
133  break;
134 
135  case 3:
136  VtkUtils::layoutRenderers<3>(renderers);
137  break;
138 
139  case 4:
140  VtkUtils::layoutRenderers<4>(renderers);
141  break;
142 
143  case 5:
144  VtkUtils::layoutRenderers<5>(renderers);
145  break;
146 
147  case 6:
148  VtkUtils::layoutRenderers<6>(renderers);
149  break;
150 
151  case 7:
152  VtkUtils::layoutRenderers<7>(renderers);
153  break;
154 
155  case 8:
156  VtkUtils::layoutRenderers<8>(renderers);
157  break;
158 
159  case 9:
160  VtkUtils::layoutRenderers<9>(renderers);
161  break;
162 
163  case 10:
165  break;
166 
167  default:
168  VtkUtils::layoutRenderers<-1>(renderers);
169  }
170 }
171 
172 void VtkWidgetPrivate::init() { layoutRenderers(); }
173 
174 // Max click duration for enabling picking mode (in ms)
175 // static const int CC_MAX_PICKING_CLICK_DURATION_MS = 200;
176 static const int CC_MAX_PICKING_CLICK_DURATION_MS = 350;
177 QVTKWidgetCustom::QVTKWidgetCustom(QMainWindow* parentWindow,
178  ecvDisplayTools* tools,
179  bool stereoMode)
180  : QVTKOpenGLNativeWidget(parentWindow),
181  m_render(nullptr),
182  m_win(parentWindow),
183  m_tools(tools),
184  m_dataObject(nullptr),
185  m_modelActor(nullptr),
186  m_interactor(nullptr),
187  m_logoWidget(nullptr),
188  m_scalarbarWidget(nullptr),
189  m_axesWidget(nullptr),
190  m_scaleBar(nullptr),
191  m_wheelZoomUpdateTimer(nullptr) {
192  this->setWindowTitle("3D View");
193 
194  // Initialize timer for delayed 2D label update after wheel zoom
195  m_wheelZoomUpdateTimer = new QTimer(this);
196  m_wheelZoomUpdateTimer->setSingleShot(true);
197  m_wheelZoomUpdateTimer->setInterval(150); // 150ms delay
198  connect(m_wheelZoomUpdateTimer, &QTimer::timeout, this, [this]() {
199  if (m_tools) {
200  m_tools->Update2DLabel(true);
201  }
202  });
203 
204  QSurfaceFormat fmt = QVTKOpenGLNativeWidget::defaultFormat();
205  fmt.setStereo(stereoMode);
206  setFormat(fmt);
207 
208 #ifdef Q_OS_WIN
209  this->setEnableHiDPI(true);
210 #endif
211 
212  // drag & drop handling
213  setAcceptDrops(true);
214  setAttribute(Qt::WA_AcceptTouchEvents, true);
215  // setAttribute(Qt::WA_OpaquePaintEvent, true);
216  vtkObject::GlobalWarningDisplayOff();
217  d_ptr = new VtkWidgetPrivate(this);
218 }
219 
221  if (d_ptr) {
222  delete d_ptr;
223  d_ptr = nullptr;
224  }
225  if (m_scaleBar) {
226  delete m_scaleBar;
227  m_scaleBar = nullptr;
228  }
229  // Timer will be automatically deleted as child of this widget
230  m_wheelZoomUpdateTimer = nullptr;
231 }
232 
234  double min, double max) {
235  double hsv1[3];
236  double hsv2[3];
239 
240  VTK_CREATE(vtkLookupTable, lut);
241  lut->SetHueRange(hsv1[0], hsv2[0]);
242  lut->SetSaturationRange(hsv1[1], hsv2[1]);
243  lut->SetValueRange(hsv1[2], hsv2[2]);
244  lut->SetTableRange(min, max);
245  lut->Build();
246 
247  return lut;
248 }
249 
251  vtkSmartPointer<vtkRenderWindowInteractor> interactor, bool useVBO) {
252  this->m_useVBO = useVBO;
253  this->m_interactor = interactor;
254 
255  this->m_render =
256  this->GetRenderWindow()->GetRenderers()->GetFirstRenderer();
257  this->m_camera = m_render->GetActiveCamera();
258  this->m_renders = this->GetRenderWindow()->GetRenderers();
259  if (!m_scaleBar) {
261  }
262 }
263 
264 void QVTKWidgetCustom::transformCameraView(const double* viewMat) {
265  vtkSmartPointer<vtkTransform> viewTransform =
267  viewTransform->SetMatrix(viewMat);
268  vtkSmartPointer<vtkCamera> cam = this->m_render->GetActiveCamera();
269  cam->ApplyTransform(viewTransform);
270  this->m_render->SetActiveCamera(cam);
271  this->m_render->Render();
272 }
273 
274 void QVTKWidgetCustom::transformCameraProjection(const double* projMat) {
275  vtkSmartPointer<vtkMatrix4x4> ProjTransform =
277  ProjTransform->Determinant(projMat);
278  this->m_camera->SetExplicitProjectionTransformMatrix(ProjTransform);
279 }
280 
282  return QThread::currentThread() == QCoreApplication::instance()->thread();
283 }
284 
287  if (IsCalledFromMainThread() && this->GetRenderWindow()) {
288  this->GetRenderWindow()->Render();
289  } else { // only core threading enabled rendering
290  QMetaObject::invokeMethod(
291  this, [=]() { this->GetRenderWindow()->Render(); },
292  Qt::QueuedConnection);
293  }
294 }
295 
297  CCVector3d& output3D) {
298  // auto picker = GetInteractor()->GetPicker();
299  // picker->Pick(input2D.x, input2D.y, 0, m_renders->GetFirstRenderer());
300  // picker->GetPickPosition(output3D.u);
301 
302  m_render->SetDisplayPoint(input2D.x, input2D.y, input2D.z);
303  m_render->DisplayToWorld();
304  const double* world = m_render->GetWorldPoint();
305  for (int i = 0; i < 3; i++) {
306  output3D.u[i] = world[i] / world[3];
307  }
308 }
309 
311  CCVector3d& output3D) {
312  toWorldPoint(CCVector3d::fromArray(input2D.u), output3D);
313 }
314 
316  CCVector3d& displayPos) {
317  m_render->SetWorldPoint(worldPos.x, worldPos.y, worldPos.z, 1.0);
318  m_render->WorldToDisplay();
319  displayPos.x = (m_render->GetDisplayPoint())[0];
320  displayPos.y = (m_render->GetDisplayPoint())[1];
321  displayPos.z = (m_render->GetDisplayPoint())[2];
322 }
323 
325  CCVector3d& displayPos) {
326  toDisplayPoint(CCVector3d::fromArray(worldPos.u), displayPos);
327 }
328 
330  vtkSmartPointer<vtkCamera> cam = this->m_render->GetActiveCamera();
331  cam->SetPosition(pos.x, pos.y, pos.z);
332  this->m_render->SetActiveCamera(cam);
333  this->m_render->Render();
334 }
335 
337  vtkSmartPointer<vtkCamera> cam = this->m_render->GetActiveCamera();
338  cam->SetFocalPoint(pos.x, pos.y, pos.z);
339  this->m_render->SetActiveCamera(cam);
340  this->m_render->Render();
341 }
342 
344  vtkSmartPointer<vtkCamera> cam = this->m_render->GetActiveCamera();
345  cam->SetViewUp(pos.x, pos.y, pos.z);
346  this->m_render->SetActiveCamera(cam);
347  this->m_render->Render();
348 }
349 
351  const ecvColor::Rgbf& bkg2,
352  bool gradient) {
353  m_render->SetBackground2(bkg2.r, bkg2.g, bkg2.b);
354  m_render->SetBackground(bkg1.r, bkg1.g, bkg1.b);
355  m_render->SetGradientBackground(gradient);
356 }
357 
359  if (d_ptr->multiViewports != multi) {
360  d_ptr->multiViewports = multi;
361  }
362 }
363 
364 bool QVTKWidgetCustom::multiViewports() const { return d_ptr->multiViewports; }
365 
366 void QVTKWidgetCustom::addActor(vtkProp* actor, const QColor& clr) {
367  if (!actor || d_ptr->actors.contains(actor)) return;
368 
369  double vtkClr[3];
370  Utils::vtkColor(clr, vtkClr);
371 
372  d_ptr->actors.append(actor);
373 
374  if (!d_ptr->multiViewports) {
375  if (d_ptr->renderers.isEmpty()) {
376  vtkRenderer* renderer = vtkRenderer::New();
377  renderer->SetBackground(vtkClr);
378  d_ptr->configRenderer(renderer);
379  renderer->AddActor(actor);
380  GetRenderWindow()->AddRenderer(renderer);
381  d_ptr->renderers.append(renderer);
382  renderer->ResetCamera();
383  } else {
384  defaultRenderer()->SetBackground(vtkClr);
385  defaultRenderer()->AddActor(actor);
386  }
387  } else {
388  if (!defaultRendererTaken()) {
389  defaultRenderer()->SetBackground(vtkClr);
390  defaultRenderer()->AddActor(actor);
391  } else {
392  vtkRenderer* renderer = vtkRenderer::New();
393  renderer->SetBackground(vtkClr);
394  d_ptr->configRenderer(renderer);
395  renderer->AddActor(actor);
396  GetRenderWindow()->AddRenderer(renderer);
397  d_ptr->renderers.append(renderer);
398  d_ptr->layoutRenderers();
399  renderer->ResetCamera();
400  }
401  }
402 }
403 
404 void QVTKWidgetCustom::addViewProp(vtkProp* prop) {
405  if (!prop || d_ptr->props.contains(prop)) return;
406 
407  d_ptr->props.append(prop);
408 
409  if (!d_ptr->multiViewports) {
410  if (d_ptr->renderers.isEmpty()) {
411  vtkRenderer* renderer = vtkRenderer::New();
412  d_ptr->configRenderer(renderer);
413  renderer->AddViewProp(prop);
414  GetRenderWindow()->AddRenderer(renderer);
415  d_ptr->renderers.append(renderer);
416  renderer->ResetCamera();
417  } else {
418  defaultRenderer()->AddViewProp(prop);
419  }
420  } else {
421  if (!defaultRendererTaken()) {
422  defaultRenderer()->AddViewProp(prop);
423  } else {
424  vtkRenderer* renderer = vtkRenderer::New();
425  d_ptr->configRenderer(renderer);
426  renderer->AddViewProp(prop);
427  GetRenderWindow()->AddRenderer(renderer);
428  d_ptr->renderers.append(renderer);
429  d_ptr->layoutRenderers();
430  renderer->ResetCamera();
431  }
432  }
433 }
434 
435 QList<vtkProp*> QVTKWidgetCustom::actors() const { return d_ptr->actors; }
436 
438  foreach (auto actor, d_ptr->actors) actor->SetVisibility(visible);
439 }
440 
441 void QVTKWidgetCustom::setActorVisible(vtkProp* actor, bool visible) {
442  actor->SetVisibility(visible);
443 }
444 
445 bool QVTKWidgetCustom::actorVisible(vtkProp* actor) {
446  return actor->GetVisibility();
447 }
448 
449 void QVTKWidgetCustom::setBackgroundColor(const QColor& clr) {
450  if (d_ptr->backgroundColor != clr) {
451  d_ptr->backgroundColor = clr;
452 
453  foreach (vtkRenderer* renderer, d_ptr->renderers)
454  d_ptr->configRenderer(renderer);
455 
456 #if 0
457  vtkRendererCollection* renderers = GetRenderWindow()->GetRenderers();
458  vtkRenderer* renderer = renderers->GetFirstRenderer();
459  while (renderer) {
460  renderer = renderers->GetNextItem();
461  }
462 #endif
463  update();
464  }
465 }
466 
468  return d_ptr->backgroundColor;
469 }
470 
472  VtkUtils::vtkInitOnce(&d_ptr->defaultRenderer);
473  GetRenderWindow()->AddRenderer(d_ptr->defaultRenderer);
474  if (!d_ptr->renderers.contains(d_ptr->defaultRenderer))
475  d_ptr->renderers.append(d_ptr->defaultRenderer);
476  return d_ptr->defaultRenderer;
477 }
478 
480  if (!d_ptr->defaultRenderer) return false;
481  return d_ptr->defaultRenderer->GetActors()->GetNumberOfItems() != 0;
482 }
483 
484 void QVTKWidgetCustom::setBounds(double* bounds) {
486  aa(bounds, d_ptr->bounds);
487 }
488 
489 double QVTKWidgetCustom::xMin() const { return d_ptr->bounds[0]; }
490 
491 double QVTKWidgetCustom::xMax() const { return d_ptr->bounds[1]; }
492 
493 double QVTKWidgetCustom::yMin() const { return d_ptr->bounds[2]; }
494 
495 double QVTKWidgetCustom::yMax() const { return d_ptr->bounds[3]; }
496 
497 double QVTKWidgetCustom::zMin() const { return d_ptr->bounds[4]; }
498 
499 double QVTKWidgetCustom::zMax() const { return d_ptr->bounds[5]; }
500 
501 // event processing
503  m_tools->m_mouseMoved = false;
506  m_tools->m_lastMousePos = event->pos();
507 
510  m_tools->m_last_picked_id = QString();
511  }
512 
513  if ((event->buttons() & Qt::RightButton)) {
514  // right click = panning (2D translation)
516  ((QApplication::keyboardModifiers() & Qt::ControlModifier) &&
519  QApplication::setOverrideCursor(QCursor(Qt::SizeAllCursor));
520  }
521 
524  emit m_tools->rightButtonClicked(event->x(), event->y());
525  }
526  } else if (event->buttons() & Qt::LeftButton) {
527  m_tools->m_lastClickTime_ticks = m_tools->m_timer.elapsed(); // in msec
528 
529  // left click = rotation
531  QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
532  }
533 
536  emit m_tools->leftButtonClicked(event->x(), event->y());
537  }
538 
539  // do this before drawing the pivot!
541  CCVector3d P;
542  // if (m_tools->GetClick3DPos(m_tools->m_glViewport.width() / 2,
543  // m_tools->m_glViewport.height() / 2, P))
544  if (m_tools->GetClick3DPos(event->x(), event->y(), P)) {
545  ecvDisplayTools::SetPivotPoint(P, true, false);
546  }
547  }
548  } else {
549  }
550 
551  QVTKOpenGLNativeWidget::mousePressEvent(event);
552 }
553 
556  .stop(); // prevent the picking process from starting
558 
559  const int x = event->x();
560  const int y = event->y();
561 
562  CCVector3d P;
564  ecvDisplayTools::SetPivotPoint(P, true, true);
565  }
566 
567  emit m_tools->doubleButtonClicked(event->x(), event->y());
568 
569  QVTKOpenGLNativeWidget::mouseDoubleClickEvent(event);
570 }
571 
573  bool doRedraw = false;
574  Qt::KeyboardModifiers keyboardModifiers = QApplication::keyboardModifiers();
575 
577 
578  // Qt5/Qt6 compatibility: get wheel delta
579  double delta = qtCompatWheelEventDelta(event);
580 
581  if (keyboardModifiers & Qt::AltModifier) {
582  event->accept();
583 
584  // same shortcut as Meshlab: change the point size
585  float sizeModifier = (delta < 0.0 ? -1.0f : 1.0f);
587  m_tools->m_viewportParams.defaultPointSize + sizeModifier);
590  doRedraw = true;
591  } else if (keyboardModifiers & Qt::ControlModifier) {
592  event->accept();
594  // same shortcut as Meshlab: change the zNear value
595  static const int MAX_INCREMENT = 150;
597  m_tools->m_viewportParams.zNearCoef, MAX_INCREMENT + 1);
598  int newIncrement =
599  std::min(std::max(0, increment + (delta < 0 ? -1 : 1)),
600  MAX_INCREMENT); // the zNearCoef must be < 1!
601  if (newIncrement != increment) {
603  newIncrement, MAX_INCREMENT + 1);
607  doRedraw = true;
608  }
609  }
610  } else if (keyboardModifiers & Qt::ShiftModifier) {
611  event->accept();
613  // same shortcut as Meshlab: change the fov value
614  float newFOV = (m_tools->m_viewportParams.fov_deg +
615  (delta < 0 ? -1.0f : 1.0f));
616  newFOV = std::min(std::max(1.0f, newFOV), 180.0f);
617  if (newFOV != m_tools->m_viewportParams.fov_deg) {
618  ecvDisplayTools::SetFov(newFOV);
621  doRedraw = true;
622  }
623  }
624  } else if (m_tools->m_interactionFlags &
626  QVTKOpenGLNativeWidget::wheelEvent(event);
627 
628  // see QWheelEvent documentation ("distance that the wheel is rotated,
629  // in eighths of a degree")
630  float wheelDelta_deg = static_cast<float>(delta) / 8;
631  m_tools->onWheelEvent(wheelDelta_deg);
632  emit m_tools->mouseWheelRotated(wheelDelta_deg);
633  emit m_tools->cameraParamChanged();
634 
635  doRedraw = true;
636  event->accept();
637  }
638 
639  if (doRedraw) {
640  // update label and 3D name if visible
641  emit m_tools->labelmove2D(0, 0, 0, 0);
643 
644  // OPTIMIZATION: Delay 2D label update during wheel zoom to improve
645  // performance. Restart the timer on each wheel event, so labels are
646  // updated 150ms after the last wheel event, reducing frequent updates
647  // during continuous scrolling.
649  m_wheelZoomUpdateTimer->stop();
650  m_wheelZoomUpdateTimer->start();
651  }
652 
654  }
655 }
656 
663  // lock axis
669  (event->buttons() & Qt::LeftButton) &&
671  event->accept();
672  } else { // normal
673  QVTKOpenGLNativeWidget::mouseMoveEvent(event);
675  }
676  }
677  }
678 
679  const int x = event->x();
680  const int y = event->y();
681  // update mouse coordinate in status bar
682  m_tools->m_lastMouseMovePos = event->pos();
683  emit m_tools->mousePosChanged(event->pos());
684 
687  emit m_tools->mouseMoved(x, y, event->buttons());
688  event->accept();
689  }
690 
691  // no button pressed
692  if (event->buttons() == Qt::NoButton) {
695  // what would be the size of the 'hot zone' if it was displayed with
696  // all options
697  if (!m_tools->m_hotZone) {
699  }
700  QRect areaRect = m_tools->m_hotZone->rect(
703 
704  const int retinaScale = ecvDisplayTools::GetDevicePixelRatio();
705  bool inZone =
706  (x * retinaScale * 3 <
707  m_tools->m_hotZone->topCorner.x() +
708  areaRect.width() * 4 // 25% margin
709  && y * retinaScale * 2 <
710  m_tools->m_hotZone->topCorner.y() +
711  areaRect.height() * 4); // 50% margin
712 
713  if (inZone != m_tools->m_clickableItemsVisible) {
715  ecvDisplayTools::RedrawDisplay(true, false);
716  }
717 
718  event->accept();
719  }
720 
721  // display the 3D coordinates of the pixel below the mouse cursor (if
722  // possible)
724  CCVector3d P;
725  QString message = QString("2D (%1 ; %2)").arg(x).arg(y);
727  message += QString(" --> 3D (%1 ; %2 ; %3)")
728  .arg(P.x)
729  .arg(P.y)
730  .arg(P.z);
731  }
733  message, ecvDisplayTools::LOWER_LEFT_MESSAGE, false, 5,
736  }
737 
738  // don't need to process any further
739  return;
740  }
741 
742  int dx = x - m_tools->m_lastMousePos.x();
743  int dy = y - m_tools->m_lastMousePos.y();
744 
745  if ((event->buttons() & Qt::RightButton)) {
746  // OPTIMIZATION: Skip 2D label updates during zoom to improve
747  // performance Only emit signal for label movement, but skip expensive
748  // Update2DLabel during zoom The label will be updated when zoom stops
749  // (in mouseReleaseEvent)
750  if (abs(dx) > 0 || abs(dy) > 0) {
751  // Only emit signal for label movement, but skip expensive
752  // Update2DLabel during zoom
753  emit m_tools->labelmove2D(x, y, 0, 0);
755  }
756  } else if ((event->buttons() & Qt::MiddleButton)) {
757  // right button = panning / translating
759  // displacement vector (in "3D")
760  double pixSize = ecvDisplayTools::ComputeActualPixelSize();
761  CCVector3d u(dx * pixSize, -dy * pixSize, 0.0);
764  }
765 
766  const int retinaScale = ecvDisplayTools::GetDevicePixelRatio();
767  u *= retinaScale;
768 
769  bool entityMovingMode =
772  ((QApplication::keyboardModifiers() &
773  Qt::ControlModifier) &&
775  if (entityMovingMode) {
776  // apply inverse view matrix
778 
781  emit m_tools->translation(u);
782  } else if (m_tools->m_customLightEnabled) {
783  // update custom light position
784  m_tools->m_customLightPos[0] += static_cast<float>(u.x);
785  m_tools->m_customLightPos[1] += static_cast<float>(u.y);
786  m_tools->m_customLightPos[2] += static_cast<float>(u.z);
789  }
790  } else // camera moving mode
791  {
793  // inverse displacement in object-based mode
794  u = -u;
795  }
796  ecvDisplayTools::MoveCamera(static_cast<float>(u.x),
797  static_cast<float>(u.y),
798  static_cast<float>(u.z));
799  }
800 
801  } // if (m_interactionFlags & INTERACT_PAN)
802 
804  // on the first time, let's check if the mouse is on a (selected) 2D
805  // item
806  if (!m_tools->m_mouseMoved) {
808  // DGM: in fact we still need to move labels in those modes
809  // below (see the 'Point Picking' tool of CLOUDVIEWER for
810  // instance)
811  //&& m_pickingMode != POINT_PICKING
812  //&& m_pickingMode != TRIANGLE_PICKING
813  //&& m_pickingMode != POINT_OR_TRIANGLE_PICKING
814  && (QApplication::keyboardModifiers() == Qt::NoModifier ||
815  QApplication::keyboardModifiers() ==
816  Qt::ControlModifier)) {
818  m_tools->m_lastMousePos.x(),
819  m_tools->m_lastMousePos.y(), true);
820  }
821  }
822  }
823 
824  // OPTIMIZATION: Skip 2D label updates during panning to improve
825  // performance Only emit signal for label movement, but skip expensive
826  // Update2DLabel during panning The label will be updated when panning
827  // stops (in mouseReleaseEvent)
828  if (abs(dx) > 0 || abs(dy) > 0) {
829  // Only emit signal for label movement, but skip expensive
830  // Update2DLabel during panning
831  emit m_tools->labelmove2D(x, y, dx, dy);
833  // specific case: move active item(s)
834  if (!m_tools->m_activeItems.empty()) {
836  }
837  }
838  } else if (event->buttons() & Qt::LeftButton) // rotation
839  {
841 
843  // on the first time, let's check if the mouse is on a (selected) 2D
844  // item
845  if (!m_tools->m_mouseMoved) {
847  // DGM: in fact we still need to move labels in those modes
848  // below (see the 'Point Picking' tool of CLOUDVIEWER for
849  // instance)
850  //&& m_pickingMode != POINT_PICKING
851  //&& m_pickingMode != TRIANGLE_PICKING
852  //&& m_pickingMode != POINT_OR_TRIANGLE_PICKING
853  && (QApplication::keyboardModifiers() == Qt::NoModifier ||
854  QApplication::keyboardModifiers() ==
855  Qt::ControlModifier)) {
857  m_tools->m_lastMousePos.x(),
858  m_tools->m_lastMousePos.y(), true);
859  }
860  }
861  } else {
862  // assert(m_tools->m_activeItems.empty());
863  m_tools->m_activeItems.clear();
864  }
865 
866  // update label and 3D name if visible
867  if (abs(dx) > 0 || abs(dy) > 0) {
868  emit m_tools->labelmove2D(x, y, dx, dy);
870  }
871 
872  // specific case: move active item(s)
873  if (!m_tools->m_activeItems.empty()) {
874  if (abs(dx) > 0 || abs(dy) > 0) {
876  }
877  } else {
878  // OPTIMIZATION: Skip 2D label updates during camera rotation to
879  // improve performance Only update when actively moving 2D items,
880  // not during camera rotation The label will be updated when
881  // rotation stops (in mouseReleaseEvent)
882  if (abs(dx) > 0 || abs(dy) > 0) {
883  // Only emit signal for label movement, but skip expensive
884  // Update2DLabel during rotation
885  emit m_tools->labelmove2D(x, y, dx, dy);
887  // specific case: move active item(s)
888  if (!m_tools->m_activeItems.empty()) {
889  updateActivateditems(x, y, dx, dy,
891  }
892  m_tools->m_activeItems.clear();
893  }
894 
895  // specific case: rectangular polyline drawing (for rectangular area
896  // selection mode)
902  (QApplication::keyboardModifiers() & Qt::AltModifier))) {
903  // first time: initialization of the rectangle
904  if (!m_tools->m_rectPickingPoly) {
905  ccPointCloud* vertices = new ccPointCloud("rect.vertices");
906  m_tools->m_rectPickingPoly = new ccPolyline(vertices);
907  m_tools->m_rectPickingPoly->addChild(vertices);
908  if (vertices->reserve(4) &&
915  // QPointF posA =
916  // ecvDisplayTools::ToCenteredGLCoordinates(m_tools->m_lastMousePos.x(),
917  // m_tools->m_lastMousePos.y());
919  m_tools->m_lastMousePos.x(),
920  m_tools->m_lastMousePos.y());
921 
922  CCVector3 A(static_cast<PointCoordinateType>(pos3D.x),
923  static_cast<PointCoordinateType>(pos3D.y),
924  pos3D.z);
925  // we add 4 times the same point (just to fill the
926  // cloud!)
927  vertices->addPoint(A);
928  vertices->addPoint(A);
929  vertices->addPoint(A);
930  vertices->addPoint(A);
933  false);
934  } else {
936  "[ QVTKWidgetCustom::mouseMoveEvent] Failed to "
937  "create seleciton polyline! Not enough "
938  "memory!");
939  delete m_tools->m_rectPickingPoly;
940  m_tools->m_rectPickingPoly = nullptr;
941  vertices = nullptr;
942  }
943  }
944 
945  if (m_tools->m_rectPickingPoly) {
948  assert(vertices);
949  CCVector3* B = const_cast<CCVector3*>(
950  vertices->getPointPersistentPtr(1));
951  CCVector3* C = const_cast<CCVector3*>(
952  vertices->getPointPersistentPtr(2));
953  CCVector3* D = const_cast<CCVector3*>(
954  vertices->getPointPersistentPtr(3));
955  // QPointF posD =
956  // ecvDisplayTools::ToCenteredGLCoordinates(event->x(),
957  // event->y());
959  event->x(), event->y());
960  B->x = C->x = static_cast<PointCoordinateType>(pos2D.x);
961  C->y = D->y = static_cast<PointCoordinateType>(pos2D.y);
962  }
963  }
964  // standard rotation around the current pivot
965  else if (m_tools->m_interactionFlags &
967  // choose the right rotation mode
968  enum RotationMode {
969  StandardMode,
970  BubbleViewMode,
971  LockedAxisMode
972  };
973  RotationMode rotationMode = StandardMode;
978  rotationMode = BubbleViewMode;
979  else if (m_tools->m_rotationAxisLocked)
980  rotationMode = LockedAxisMode;
981  }
982 
983  ccGLMatrixd rotMat;
984  switch (rotationMode) {
985  case BubbleViewMode: {
986  QPoint posDelta =
987  m_tools->m_lastMousePos - event->pos();
988 
989  if (std::abs(posDelta.x()) != 0) {
990  double delta_deg =
991  (posDelta.x() *
992  static_cast<double>(
994  height();
995  // rotation about the sensor Z axis
997  .getColumnAsVec3D(2);
998  rotMat.initFromParameters(
1000  axis, CCVector3d(0, 0, 0));
1001  }
1002 
1003  if (std::abs(posDelta.y()) != 0) {
1004  double delta_deg =
1005  (posDelta.y() *
1006  static_cast<double>(
1008  height();
1009  // rotation about the local X axis
1010  ccGLMatrixd rotX;
1011  rotX.initFromParameters(
1012  cloudViewer::DegreesToRadians(delta_deg),
1013  CCVector3d(1, 0, 0), CCVector3d(0, 0, 0));
1014  rotMat = rotX * rotMat;
1015  }
1016  } break;
1017 
1018  case StandardMode: {
1019  static CCVector3d s_lastMouseOrientation;
1020  if (!m_tools->m_mouseMoved) {
1021  // on the first time, we must compute the previous
1022  // orientation (the camera hasn't moved yet)
1023  s_lastMouseOrientation = ecvDisplayTools::
1025  m_tools->m_lastMousePos.x(),
1026  m_tools->m_lastMousePos.y());
1027  }
1028 
1029  CCVector3d currentMouseOrientation = ecvDisplayTools::
1031  rotMat = ccGLMatrixd::FromToRotation(
1032  s_lastMouseOrientation,
1033  currentMouseOrientation);
1034  s_lastMouseOrientation = currentMouseOrientation;
1035  } break;
1036 
1037  case LockedAxisMode: {
1038  // apply rotation about the locked axis
1040  // m_tools->m_viewportParams.objectCenteredView
1041  ccGLCameraParameters camera;
1043  camera.modelViewMat.applyRotation(axis);
1044 
1045  // determine whether we are in a side or top view
1046  bool topView = (std::abs(axis.z) > 0.5);
1047  double angle_rad = 0.0;
1048  if (topView) {
1049  // rotation origin
1050  CCVector3d C2D;
1052  // project the current pivot point on screen
1054  .getPivotPoint(),
1055  C2D);
1056  C2D.z = 0.0;
1057  } else {
1058  C2D = CCVector3d(width() / 2.0, height() / 2.0,
1059  0.0);
1060  }
1061 
1062  CCVector3d previousMousePos(
1063  static_cast<double>(
1064  m_tools->m_lastMousePos.x()),
1065  static_cast<double>(
1066  height() -
1067  m_tools->m_lastMousePos.y()),
1068  0.0);
1069  CCVector3d currentMousePos(
1070  static_cast<double>(x),
1071  static_cast<double>(height() - y), 0.0);
1072 
1073  CCVector3d a = (currentMousePos - C2D);
1074  CCVector3d b = (previousMousePos - C2D);
1075  CCVector3d u = a * b;
1076  double u_norm = std::abs(
1077  u.z); // a and b are in the XY plane
1078  if (u_norm > 1.0e-6) {
1079  double sin_angle =
1080  u_norm / (a.norm() * b.norm());
1081 
1082  // determine the rotation direction
1083  if (u.z * m_tools->m_lockedRotationAxis.z > 0) {
1084  sin_angle = -sin_angle;
1085  }
1086 
1087  angle_rad =
1088  asin(sin_angle); // in [-pi/2 ; pi/2]
1089  rotMat.initFromParameters(angle_rad, axis,
1090  CCVector3d(0, 0, 0));
1091  }
1092  } else // side view
1093  {
1094  // project the current pivot point on screen
1095  CCVector3d A2D, B2D;
1096  if (camera.project(m_tools->m_viewportParams
1097  .getPivotPoint(),
1098  A2D) &&
1099  camera.project(
1101  .getPivotPoint() +
1104  B2D)) {
1105  CCVector3d lockedRotationAxis2D = B2D - A2D;
1106  lockedRotationAxis2D.z = 0; // just in case
1107  lockedRotationAxis2D.normalize();
1108 
1109  CCVector3d mouseShift(static_cast<double>(dx),
1110  -static_cast<double>(dy),
1111  0.0);
1112  mouseShift -=
1113  mouseShift.dot(lockedRotationAxis2D) *
1114  lockedRotationAxis2D; // we only keep
1115  // the orthogonal
1116  // part
1117  angle_rad = 2.0 * M_PI * mouseShift.norm() /
1118  (width() + height());
1119  if ((lockedRotationAxis2D * mouseShift).z >
1120  0.0) {
1121  angle_rad = -angle_rad;
1122  }
1123 
1124  rotMat.initFromParameters(angle_rad, axis,
1125  CCVector3d(0, 0, 0));
1126  }
1127  }
1128 
1129  // rotate camera with axis
1130  // Note: -cloudViewer::RadiansToDegrees(angle_rad):
1131  // inverse direction rotation
1134  -cloudViewer::RadiansToDegrees(angle_rad));
1135  } break;
1136 
1137  default:
1138  assert(false);
1139  break;
1140  }
1141 
1145  rotMat * m_tools->m_viewportParams.viewMat;
1146  // feedback for 'interactive transformation' mode
1147  emit m_tools->rotation(rotMat);
1148  } else {
1149  // ecvDisplayTools::RotateBaseViewMat(rotMat);
1151  QApplication::changeOverrideCursor(
1152  QCursor(Qt::ClosedHandCursor));
1153 
1154  // feedback for 'echo' mode
1155  emit m_tools->viewMatRotated(rotMat);
1156  }
1157  }
1158  }
1159  }
1160 
1161  m_tools->m_mouseMoved = true;
1162  m_tools->m_lastMousePos = event->pos();
1163  emit m_tools->cameraParamChanged();
1165  event->accept();
1166 }
1167 
1169  int x, int y, int dx, int dy, bool updatePosition) {
1170  if (updatePosition) {
1171  // displacement vector (in "3D")
1172  double pixSize = ecvDisplayTools::ComputeActualPixelSize();
1173  CCVector3d u(dx * pixSize, -dy * pixSize, 0.0);
1175 
1176  const int retinaScale = ecvDisplayTools::GetDevicePixelRatio();
1177  u *= retinaScale;
1178 
1179  for (auto& activeItem : m_tools->m_activeItems) {
1180  if (activeItem->move2D(x * retinaScale, y * retinaScale,
1181  dx * retinaScale, dy * retinaScale,
1185  } else if (activeItem->move3D(u)) {
1188  }
1189  }
1190  }
1191 
1193 }
1194 
1197  QVTKOpenGLNativeWidget::mouseReleaseEvent(event);
1198  }
1199 
1202  return;
1203  }
1204  bool mouseHasMoved = m_tools->m_mouseMoved;
1205 
1206  // reset to default state
1207  m_tools->m_mouseButtonPressed = false;
1208  m_tools->m_mouseMoved = false;
1209  QApplication::restoreOverrideCursor();
1210 
1213  event->accept();
1214  emit m_tools->buttonReleased();
1215  }
1216 
1217  if (m_tools->m_pivotSymbolShown) {
1220  }
1223  }
1224 
1225  if ((event->button() == Qt::MiddleButton)) {
1226  if (mouseHasMoved) {
1227  event->accept();
1228  m_tools->m_activeItems.clear();
1229  // ecvDisplayTools::ToBeRefreshed();
1230  } else if (m_tools->m_interactionFlags &
1232  // interaction with 2D item(s)
1234  false);
1235  if (!m_tools->m_activeItems.empty()) {
1236  ccInteractor* item = m_tools->m_activeItems.front();
1237  m_tools->m_activeItems.clear();
1238  if (item->acceptClick(event->x(), height() - 1 - event->y(),
1239  Qt::MiddleButton)) {
1240  event->accept();
1241  }
1242  }
1243  }
1244  } else if (event->button() == Qt::LeftButton) {
1245  if (mouseHasMoved) {
1246  // if a rectangular picking area has been defined
1247  if (m_tools->m_rectPickingPoly) {
1250  assert(vertices);
1251  const CCVector3* A = vertices->getPointPersistentPtr(0);
1252  const CCVector3* C = vertices->getPointPersistentPtr(2);
1253 
1254  int pickX = static_cast<int>(A->x + C->x) / 2;
1255  int pickY = static_cast<int>(A->y + C->y) / 2;
1256  int pickW = static_cast<int>(std::abs(C->x - A->x));
1257  int pickH = static_cast<int>(std::abs(C->y - A->y));
1258 
1260  m_tools->m_rectPickingPoly = nullptr;
1261  vertices = nullptr;
1262 
1265  pickX + ecvDisplayTools::Width() / 2,
1266  ecvDisplayTools::Height() / 2 - pickY, pickW, pickH);
1269  }
1270 
1271  event->accept();
1272  } else {
1273  // picking?
1274  // CRITICAL: Don't start deferred picking if a VTK widget was
1275  // clicked This prevents doPicking() from overriding the widget
1276  // selection
1277  if (!m_tools->m_widgetClicked &&
1278  m_tools->m_timer.elapsed() <
1281  {
1282  int x = m_tools->m_lastMousePos.x();
1283  int y = m_tools->m_lastMousePos.y();
1284 
1285  // first test if the user has clicked on a particular item on
1286  // the screen
1289  event->pos(); // just in case (it should be already
1290  // at this position)
1292  }
1293  } else if (m_tools->m_widgetClicked) {
1295  "[QVTKWidgetCustom::mouseReleaseEvent] Skipping "
1296  "deferred "
1297  "picking because VTK widget was clicked");
1298  // Reset the flag after checking
1299  m_tools->m_widgetClicked = false;
1300  }
1301  }
1302 
1303  m_tools->m_activeItems.clear();
1304  } else if (event->button() == Qt::RightButton) {
1305  // CRITICAL: Update 2D labels after zoom/scale to ensure they align with
1306  // their 3D anchor points
1307  if (mouseHasMoved) {
1308  m_tools->Update2DLabel(true);
1309  }
1310  }
1311 
1312  // CRITICAL: Always update 2D labels after any mouse interaction that moved
1313  // the camera (rotation, zoom, pan) to ensure labels stay aligned with their
1314  // 3D anchor points. This fixes the issue where labels become detached after
1315  // mouse release.
1316  if (mouseHasMoved) {
1317  m_tools->Update2DLabel(true);
1318  }
1319 
1321 }
1322 
1323 void QVTKWidgetCustom::dragEnterEvent(QDragEnterEvent* event) {
1324  const QMimeData* mimeData = event->mimeData();
1325  if (mimeData->hasFormat("text/uri-list")) event->acceptProposedAction();
1326 
1327  QVTKOpenGLNativeWidget::dragEnterEvent(event);
1328 }
1329 
1331  const QMimeData* mimeData = event->mimeData();
1332 
1333  if (mimeData && mimeData->hasFormat("text/uri-list")) {
1334  QStringList fileNames;
1335  for (const QUrl& url : mimeData->urls()) {
1336  QString fileName = url.toLocalFile();
1337  fileNames.append(fileName);
1338 #ifdef QT_DEBUG
1339  CVLog::Print(QString("File dropped: %1").arg(fileName));
1340 #endif
1341  }
1342 
1343  if (!fileNames.empty()) {
1344  emit m_tools->filesDropped(fileNames, true);
1345  }
1346 
1347  event->acceptProposedAction();
1348  }
1349 
1350  QVTKOpenGLNativeWidget::dropEvent(event);
1351  event->ignore();
1352 }
1353 
1354 bool QVTKWidgetCustom::event(QEvent* evt) {
1355  switch (evt->type()) {
1356  // Gesture start/stop
1357  case QEvent::TouchBegin:
1358  case QEvent::TouchEnd: {
1359  QTouchEvent* touchEvent = static_cast<QTouchEvent*>(evt);
1360  touchEvent->accept();
1361  m_tools->m_touchInProgress = (evt->type() == QEvent::TouchBegin);
1362  m_tools->m_touchBaseDist = 0.0;
1363  CVLog::PrintDebug(QString("Touch event %1")
1365  ? "begins"
1366  : "ends"));
1367  } break;
1368 
1369  case QEvent::Close: {
1370  if (m_unclosable) {
1371  evt->ignore();
1372  } else {
1373  evt->accept();
1374  }
1375  }
1376  return true;
1377 
1378  case QEvent::DragEnter: {
1379  dragEnterEvent(static_cast<QDragEnterEvent*>(evt));
1380  }
1381  return true;
1382 
1383  case QEvent::Drop: {
1384  dropEvent(static_cast<QDropEvent*>(evt));
1385  }
1386  return true;
1387 
1388  case QEvent::TouchUpdate: {
1389  // Gesture update
1390  if (m_tools->m_touchInProgress &&
1392  QTouchEvent* touchEvent = static_cast<QTouchEvent*>(evt);
1393  const QList<QTouchEvent::TouchPoint>& touchPoints =
1394  touchEvent->touchPoints();
1395  if (touchPoints.size() == 2) {
1396  QPointF D = (touchPoints[1].pos() - touchPoints[0].pos());
1397  qreal dist = std::sqrt(D.x() * D.x() + D.y() * D.y());
1398  if (m_tools->m_touchBaseDist != 0.0) {
1399  float zoomFactor = dist / m_tools->m_touchBaseDist;
1400  ecvDisplayTools::UpdateZoom(zoomFactor);
1401  }
1402  m_tools->m_touchBaseDist = dist;
1403  evt->accept();
1404  break;
1405  }
1406  }
1407  } break;
1408 
1409  case QEvent::Resize: {
1410  QSize newSize = static_cast<QResizeEvent*>(evt)->size();
1411  ecvDisplayTools::ResizeGL(newSize.width(), newSize.height());
1413  evt->accept();
1414  } break;
1415 
1416  case QEvent::KeyPress: {
1417  // Handle ESC key before VTK interactor processes it
1418  // This ensures ESC works to exit selection tools
1419  QKeyEvent* keyEvent = static_cast<QKeyEvent*>(evt);
1420  if (keyEvent->key() == Qt::Key_Escape) {
1421  CVLog::Print(
1422  "[QVTKWidgetCustom] ESC key pressed, forwarding to "
1423  "MainWindow");
1424 
1425  // Handle fullscreen toggle
1426  emit m_tools->exclusiveFullScreenToggled(false);
1427 
1428  // Forward ESC to MainWindow to handle selection tools
1429  if (m_win) {
1430  // Use postEvent to ensure it goes through MainWindow's
1431  // event loop
1432  QKeyEvent* newEvent =
1433  new QKeyEvent(QEvent::KeyPress, Qt::Key_Escape,
1434  keyEvent->modifiers());
1435  QCoreApplication::postEvent(m_win, newEvent);
1436  }
1437  evt->accept();
1438  return true; // Event handled, don't pass to VTK
1439  }
1440  } break;
1441 
1442  default: {
1443  // CVLog::Print("Unhandled event: %i", evt->type());
1444  } break;
1445  }
1446 
1447  return QVTKOpenGLNativeWidget::event(evt);
1448 }
1449 
1451  // ESC is already handled in event() before VTK processes it
1452  // Other keys are passed to the base class
1453  QVTKOpenGLNativeWidget::keyPressEvent(event);
1454 }
MouseEvent event
constexpr double M_PI
Pi.
Definition: CVConst.h:19
Vector2Tpl< int > CCVector2i
Int 2D Vector.
Definition: CVGeom.h:786
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int width
int size
int height
int count
static const int CC_MAX_PICKING_CLICK_DURATION_MS
static int columnCount(int count)
#define VTK_CREATE(TYPE, NAME)
bool IsCalledFromMainThread()
double qtCompatWheelEventDelta(const QWheelEvent *event) noexcept
Definition: QtCompat.h:751
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
Definition: CVLog.cpp:153
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
static bool PrintVerbose(const char *format,...)
Prints out a verbose formatted message in console.
Definition: CVLog.cpp:103
Container widget for vtk.
virtual void mouseReleaseEvent(QMouseEvent *event) override
virtual void mouseMoveEvent(QMouseEvent *event) override
double zMax() const
VtkWidgetPrivate * d_ptr
void setActorVisible(vtkProp *actor, bool visible)
ScaleBarWidget * m_scaleBar
vtkRenderer * m_render
QTimer * m_wheelZoomUpdateTimer
void toWorldPoint(const CCVector3d &input2D, CCVector3d &output3D)
bool defaultRendererTaken() const
void setBounds(double *bounds)
QColor backgroundColor() const
double xMax() const
virtual void updateActivateditems(int x, int y, int dx, int dy, bool updatePosition=false)
void transformCameraProjection(const double *projMat)
void addActor(vtkProp *actor, const QColor &clr=Qt::black)
vtkRenderWindow * GetRenderWindow()
virtual void mousePressEvent(QMouseEvent *event) override
QMainWindow * m_win
ecvDisplayTools * m_tools
virtual void dropEvent(QDropEvent *event) override
double yMin() const
double zMin() const
void setCameraFocalPoint(const CCVector3d &pos)
void transformCameraView(const double *viewMat)
vtkSmartPointer< vtkLookupTable > createLookupTable(double min, double max)
void initVtk(vtkSmartPointer< vtkRenderWindowInteractor > interactor, bool useVBO=false)
virtual void keyPressEvent(QKeyEvent *event) override
virtual void dragEnterEvent(QDragEnterEvent *event) override
bool actorVisible(vtkProp *actor)
void setMultiViewports(bool multi=true)
double xMin() const
vtkSmartPointer< vtkCamera > m_camera
void toDisplayPoint(const CCVector3d &worldPos, CCVector3d &displayPos)
QList< vtkProp * > actors() const
void addViewProp(vtkProp *prop)
QVTKWidgetCustom(QMainWindow *parentWindow, ecvDisplayTools *tools, bool stereoMode=false)
void setActorsVisible(bool visible)
vtkSmartPointer< vtkRenderWindowInteractor > m_interactor
void setCameraViewUp(const CCVector3d &pos)
vtkRenderer * defaultRenderer()
virtual bool event(QEvent *evt) override
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
bool multiViewports() const
double yMax() const
void setCameraPosition(const CCVector3d &pos)
virtual void wheelEvent(QWheelEvent *event) override
vtkSmartPointer< vtkRendererCollection > m_renders
void setBackgroundColor(const QColor &clr)
void update(vtkRenderer *renderer, vtkRenderWindowInteractor *interactor)
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
void normalize()
Sets vector norm to unity.
Definition: CVGeom.h:428
Type dot(const Vector3Tpl &v) const
Dot product.
Definition: CVGeom.h:408
Type norm() const
Returns vector norm.
Definition: CVGeom.h:424
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
Definition: CVGeom.h:268
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showColors(bool state)
Sets colors visibility.
ccGLMatrixTpl< T > transposed() const
Returns transposed matrix.
void applyRotation(Vector3Tpl< float > &vec) const
Applies rotation only to a 3D vector (in place) - float version.
static ccGLMatrixTpl< double > FromToRotation(const Vector3Tpl< double > &from, const Vector3Tpl< double > &to)
Creates a transformation matrix that rotates a vector to another.
Vector3Tpl< T > getColumnAsVec3D(unsigned index) const
Returns a copy of a given column as a CCVector3.
void initFromParameters(T alpha_rad, const Vector3Tpl< T > &axis3D, const Vector3Tpl< T > &t3D)
Inits transformation from a rotation axis, an angle and a translation.
Double version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:56
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Definition: ecvHObject.cpp:534
Interactor interface (entity that can be dragged or clicked in a 3D view)
Definition: ecvInteractor.h:20
virtual bool acceptClick(int x, int y, Qt::MouseButton button)
Called on mouse click.
Definition: ecvInteractor.h:25
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
Colored polyline.
Definition: ecvPolyline.h:24
void setForeground(bool state)
Defines if the polyline is drawn in background or foreground.
void set2DMode(bool state)
Defines if the polyline is considered as 2D or 3D.
void setColor(const ecvColor::Rgb &col)
Sets the polyline color.
Definition: ecvPolyline.h:81
A generic 3D point cloud with index-based and presistent access to points.
virtual const CCVector3 * getPointPersistentPtr(unsigned index)=0
Returns the ith point as a persistent pointer.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
void setClosed(bool state)
Sets whether the polyline is closed or not.
Definition: Polyline.h:29
virtual bool addPointIndex(unsigned globalIndex)
Point global index insertion mechanism.
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
RGB color structure.
Definition: ecvColorTypes.h:49
void doubleButtonClicked(int x, int y)
Signal emitted when the double mouse button is cliked on the window.
QTimer m_deferredPickingTimer
Deferred picking.
static int GetDevicePixelRatio()
static bool ExclusiveFullScreen()
Returns whether the window is in exclusive full screen mode or not.
bool m_customLightEnabled
Whether custom light is enabled or not.
float m_bubbleViewFov_deg
Bubble-view mode f.o.v. (degrees)
bool m_ignoreMouseReleaseEvent
Ignore next mouse release event.
bool m_rotationAxisLocked
Wheter the rotation axis is locked or not.
static void Update()
void cameraParamChanged()
static INTERACTION_FLAGS TRANSFORM_CAMERA()
static CCVector3d ConvertMousePositionToOrientation(int x, int y)
Converts a given (mouse) position in pixels to an orientation.
static void RemoveFromOwnDB(ccHObject *obj)
Removes an entity from window own DB.
static void SetPointSize(float size, bool silent=false, int viewport=0)
static void SetPivotPoint(const CCVector3d &P, bool autoUpdateCameraPos=false, bool verbose=false)
Sets pivot point.
void leftButtonClicked(int x, int y)
Signal emitted when the left mouse button is cliked on the window.
void onWheelEvent(float wheelDelta_deg)
INTERACTION_FLAGS m_interactionFlags
Current intercation flags.
static void GetGLCameraParameters(ccGLCameraParameters &params)
Returns the current OpenGL camera parameters.
qreal m_touchBaseDist
Touch gesture initial distance.
static void InvalidateViewport()
bool m_touchInProgress
Touch event in progress.
CCVector3d m_lockedRotationAxis
Locked rotation axis.
static void StartPicking(PickingParameters &params)
Starts picking process.
std::list< ccInteractor * > m_activeItems
Currently active items.
void viewMatRotated(const ccGLMatrixd &rotMat)
static bool USE_2D
static int Height()
HotZone * m_hotZone
Hot zone.
void rotation(const ccGLMatrixd &rotMat)
Signal emitted when the selected object is rotated by the user.
static void UpdateZoom(float zoomFactor)
Updates current zoom.
void mouseWheelChanged(QWheelEvent *event)
static bool GetClick3DPos(int x, int y, CCVector3d &P3D)
Returns the approximate 3D position of the clicked pixel.
static int GlWidth()
Returns the OpenGL context width.
void mousePosChanged(const QPoint &pos)
void mouseMoved(int x, int y, Qt::MouseButtons buttons)
Signal emitted when the mouse is moved.
void mouseWheelRotated(float wheelDelta_deg)
Signal emitted when the mouse wheel is rotated.
bool m_allowRectangularEntityPicking
Whether rectangular picking is allowed or not.
static int Width()
static void Deprecate3DLayer()
ecvViewportParameters m_viewportParams
Viewport parameters (zoom, etc.)
static void ToBeRefreshed()
static int GlHeight()
Returns the OpenGL context height.
static bool ProcessClickableItems(int x, int y)
Processes the clickable items.
static void SetRedrawRecursive(bool redraw=false)
void scheduleFullRedraw(unsigned maxDelay_ms)
Schedules a full redraw.
static void SetZNearCoef(double coef)
Sets current camera 'zNear' coefficient.
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
bool m_mouseMoved
Whether the mouse (cursor) has moved after being pressed or not.
static void AddToOwnDB(ccHObject *obj, bool noDependency=true)
Adds an entity to window own DB.
static void RotateWithAxis(const CCVector2i &pos, const CCVector3d &axis, double angle, int viewport=0)
static void ShowPivotSymbol(bool state)
Shows or hide the pivot symbol.
ccPolyline * m_rectPickingPoly
Rectangular picking polyline.
static void RefreshDisplay(bool only2D=false, bool forceRedraw=true)
static bool USE_VTK_PICK
bool m_bubbleViewModeEnabled
Bubble-view mode state.
QElapsedTimer m_timer
Internal timer.
void translation(const CCVector3d &t)
Signal emitted when the selected object is translated by the user.
static void ResizeGL(int w, int h)
Sets current zoom.
void exclusiveFullScreenToggled(bool exclusive)
Signal emitted when the exclusive fullscreen is toggled.
void filesDropped(const QStringList &filenames, bool displayDialog)
Signal emitted when files are dropped on the window.
PivotVisibility m_pivotVisibility
Pivot symbol visibility.
bool m_pivotSymbolShown
Whether pivot symbol should be shown or not.
static void Redraw2DLabel()
void labelmove2D(int x, int y, int dx, int dy)
static void DisplayNewMessage(const QString &message, MessagePosition pos, bool append=false, int displayMaxDelay_sec=2, MessageType type=CUSTOM_MESSAGE)
Displays a status message in the bottom-left corner.
float m_customLightPos[4]
Custom light position.
static void SetFov(float fov)
Sets current camera f.o.v. (field of view) in degrees.
bool m_mouseButtonPressed
Whether the mouse is currently pressed or not.
static void UpdateNamePoseRecursive()
static void MoveCamera(float dx, float dy, float dz)
Displaces camera.
void buttonReleased()
Signal emitted when a mouse button is released (cursor on the window)
static void UpdateDisplayParameters()
static CCVector3d ToVtkCoordinates(int x, int y, int z=0)
QPoint m_lastMousePos
Last mouse position.
void rightButtonClicked(int x, int y)
Signal emitted when the right mouse button is cliked on the window.
static void UpdateActiveItemsList(int x, int y, bool extendToSelectedLabels=false)
Updates currently active items list (m_activeItems)
qint64 m_lastClickTime_ticks
Last click time (msec)
static double ComputeActualPixelSize()
PICKING_MODE m_pickingMode
bool m_clickableItemsVisible
Whether clickable items are visible (= mouse over) or not.
static void Update2DLabel(bool immediateUpdate=false)
double zNearCoef
Theoretical perspective 'zNear' relative position.
static int ZNearCoefToIncrement(double coef, int iMax)
bool perspectiveView
Perspective view state.
float fov_deg
Camera F.O.V. (field of view) in degrees.
static double IncrementToZNearCoef(int i, int iMax)
float cameraAspectRatio
Camera aspect ratio.
double zFar
Actual perspective 'zFar' value.
float defaultPointSize
Point size.
const CCVector3d & getPivotPoint() const
Returns the pivot point (for object-centered view mode)
ccGLMatrixd viewMat
Visualization matrix (rotation only)
a[190]
normal_z y
normal_z x
void vtkColor(const QColor &clr, double *vtkClr)
Definition: utils.cpp:60
void qColor2HSV(const QColor &clr, double *hsv)
Definition: utils.cpp:97
void layoutRenderers< 7 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 5 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 8 >(const QList< vtkRenderer * > &renderers)
void vtkInitOnce(T **obj)
Definition: vtkutils.h:44
void layoutRenderers< 10 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 1 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 4 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 3 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 9 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 2 >(const QList< vtkRenderer * > &renderers)
void layoutRenderers< 6 >(const QList< vtkRenderer * > &renderers)
void Resize(const core::Tensor &src_im, core::Tensor &dst_im, Image::InterpType interp_type)
Definition: IPPImage.cpp:94
float RadiansToDegrees(int radians)
Convert radians to degrees.
Definition: CVMath.h:71
float DegreesToRadians(int degrees)
Convert degrees to radians.
Definition: CVMath.h:98
constexpr Rgb black(0, 0, 0)
constexpr Rgb green(0, MAX, 0)
OpenGL camera parameters.
ccGLMatrixd modelViewMat
Model view matrix (GL_MODELVIEW)
bool project(const CCVector3d &input3D, CCVector3d &output2D, bool *inFrustum=nullptr) const
Projects a 3D point in 2D (+ normalized 'z' coordinate)
Precomputed stuff for the 'hot zone'.
QRect rect(bool clickableItemsVisible, bool bubbleViewModeEnabled, bool fullScreenEnabled) const