ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvDisplayTools.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 #ifdef USE_VLD
9 // VLD
10 #include <vld.h>
11 #endif
12 
13 // CV_CORE_LIB
14 #include <CVTools.h>
15 
16 // LOCAL
17 #include "LineSet.h"
18 #include "ecv2DLabel.h"
19 #include "ecv2DViewportLabel.h"
20 #include "ecvBBox.h"
21 #include "ecvCameraSensor.h"
22 #include "ecvClipBox.h"
23 #include "ecvDisplayTools.h"
24 #include "ecvGenericVisualizer.h"
25 #include "ecvGenericVisualizer2D.h"
26 #include "ecvGenericVisualizer3D.h"
27 #include "ecvHObjectCaster.h"
28 #include "ecvInteractor.h"
29 #include "ecvPointCloud.h"
30 #include "ecvPolyline.h"
31 #include "ecvRenderingTools.h"
32 #include "ecvSingleton.h"
33 #include "ecvSphere.h"
34 #include "ecvSubMesh.h"
35 
36 // QT
37 #include <QApplication>
38 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
39 #include <QDesktopWidget>
40 #endif
41 #include <QLayout>
42 #include <QMainWindow>
43 #include <QMessageBox>
44 #include <QPushButton>
45 #include <QScreen>
46 #include <QSettings>
47 #include <QString>
48 
49 // SYSTEM
50 #include <assert.h>
51 
52 // unique display tools instance
54 
55 bool ecvDisplayTools::USE_2D = true;
57 
58 static const QString DEBUG_LAYER_ID = "DEBUG_LAYER";
59 
60 // default interaction flags
61 ecvDisplayTools::INTERACTION_FLAGS ecvDisplayTools::PAN_ONLY() {
62  ecvDisplayTools::INTERACTION_FLAGS flags =
65  return flags;
66 }
67 ecvDisplayTools::INTERACTION_FLAGS ecvDisplayTools::TRANSFORM_CAMERA() {
68  ecvDisplayTools::INTERACTION_FLAGS flags = INTERACT_ROTATE | PAN_ONLY();
69  return flags;
70 }
71 ecvDisplayTools::INTERACTION_FLAGS ecvDisplayTools::TRANSFORM_ENTITIES() {
72  ecvDisplayTools::INTERACTION_FLAGS flags =
75  return flags;
76 }
77 
78 /*** Persistent settings ***/
79 
80 static const char c_ps_groupName[] = "ECVWindow";
81 static const char c_ps_perspectiveView[] = "perspectiveView";
82 static const char c_ps_objectMode[] = "objectCenteredView";
83 static const char c_ps_sunLight[] = "sunLightEnabled";
84 static const char c_ps_customLight[] = "customLightEnabled";
85 static const char c_ps_pivotVisibility[] = "pivotVisibility";
86 static const char c_ps_stereoGlassType[] = "stereoGlassType";
87 
88 // Vaious overlay elements dimensions
89 static const double CC_DISPLAYED_PIVOT_RADIUS_PERCENT =
90  0.8; // percentage of the smallest screen dimension
91 static const double CC_DISPLAYED_CUSTOM_LIGHT_LENGTH = 10.0;
92 static const float CC_DISPLAYED_TRIHEDRON_AXES_LENGTH = 25.0f;
93 static const float CC_TRIHEDRON_TEXT_MARGIN = 5.0f;
94 static const float CC_DISPLAYED_CENTER_CROSS_LENGTH = 10.0f;
95 
96 // Max click duration for enabling picking mode (in ms)
97 static const int CC_MAX_PICKING_CLICK_DURATION_MS = 200;
98 
99 // Unique GL window ID
100 static int s_GlWindowNumber = 0;
101 
103  QMainWindow* win,
104  bool stereoMode) {
105  // should be called only once!
106  if (s_tools.instance) {
107  assert(false);
108  return;
109  }
110 
111  s_tools.instance = displayTools;
113 
114  // start internal timer
115  s_tools.instance->m_timer.start();
116 
117  SetMainWindow(win);
118  // register current instance visualizer only once
119  s_tools.instance->registerVisualizer(win, stereoMode);
120 
121  s_tools.instance->m_uniqueID = ++s_GlWindowNumber; // GL window unique ID
122  s_tools.instance->m_lastMousePos = QPoint(-1, -1);
123  s_tools.instance->m_lastMouseMovePos = QPoint(-1, -1);
124  s_tools.instance->m_validModelviewMatrix = false;
125  s_tools.instance->m_validProjectionMatrix = false;
126  s_tools.instance->m_cameraToBBCenterDist = 0.0;
127  s_tools.instance->m_shouldBeRefreshed = false;
128  s_tools.instance->m_mouseMoved = false;
129  s_tools.instance->m_mouseButtonPressed = false;
130  s_tools.instance->m_widgetClicked = false;
131 
132  s_tools.instance->m_bbHalfDiag = 0.0;
133  s_tools.instance->m_interactionFlags = TRANSFORM_CAMERA();
134  s_tools.instance->m_pickingMode = NO_PICKING;
135  s_tools.instance->m_pickingModeLocked = false;
136  s_tools.instance->m_lastClickTime_ticks = 0;
137 
138  s_tools.instance->m_sunLightEnabled = true;
139  s_tools.instance->m_customLightEnabled = false;
140  s_tools.instance->m_clickableItemsVisible = false;
141  s_tools.instance->m_alwaysUseFBO = false;
142  s_tools.instance->m_updateFBO = true;
143  s_tools.instance->m_winDBRoot = nullptr;
144  s_tools.instance->m_globalDBRoot = nullptr; // external DB
145  s_tools.instance->m_removeFlag = false;
146  s_tools.instance->m_font = QFont();
147  s_tools.instance->m_pivotVisibility = PIVOT_SHOW_ON_MOVE;
148  s_tools.instance->m_pivotSymbolShown = false;
149  s_tools.instance->m_allowRectangularEntityPicking = false;
150  s_tools.instance->m_rectPickingPoly = nullptr;
151  s_tools.instance->m_overridenDisplayParametersEnabled = false;
152  s_tools.instance->m_displayOverlayEntities = true;
153  s_tools.instance->m_bubbleViewModeEnabled = false;
154  s_tools.instance->m_bubbleViewFov_deg = 90.0f;
155  s_tools.instance->m_touchInProgress = false;
156  s_tools.instance->m_touchBaseDist = 0.0;
157  s_tools.instance->m_scheduledFullRedrawTime = 0;
158  s_tools.instance->m_exclusiveFullscreen = false;
159  s_tools.instance->m_showDebugTraces = false;
160  s_tools.instance->m_pickRadius = DefaultPickRadius;
161  s_tools.instance->m_autoRefresh = false;
162  s_tools.instance->m_hotZone = nullptr;
163  s_tools.instance->m_showCursorCoordinates = false;
164  s_tools.instance->m_autoPickPivotAtCenter = false;
165  s_tools.instance->m_ignoreMouseReleaseEvent = false;
166  s_tools.instance->m_rotationAxisLocked = false;
167  s_tools.instance->m_lockedRotationAxis = CCVector3d(0, 0, 1);
168 
169  // GL window own DB
170  s_tools.instance->m_winDBRoot = new ccHObject(
171  QString("DB.3DView_%1").arg(s_tools.instance->m_uniqueID));
172 
173  // matrices
174  s_tools.instance->m_viewportParams.viewMat.toIdentity();
175  s_tools.instance->m_viewportParams.setCameraCenter(CCVector3d(
176  0.0, 0.0,
177  1.0)); // don't position the camera on the pivot by default!
178  s_tools.instance->m_viewMatd.toIdentity();
179  s_tools.instance->m_projMatd.toIdentity();
180 
181  // default modes
184 
185  // auto-load previous perspective settings
186  {
187  QSettings settings;
188  settings.beginGroup(c_ps_groupName);
189 
190  // load parameters
191  bool perspectiveView =
192  settings.value(c_ps_perspectiveView, false).toBool();
193  // DGM: we force object-centered view by default now, as the
194  // viewer-based perspective is too dependent on what is displayed (so
195  // restoring this parameter at next startup is rarely a good idea)
196  bool objectCenteredView =
197  /*settings.value(c_ps_objectMode, true ).toBool()*/ true;
198  int pivotVisibility =
199  settings.value(c_ps_pivotVisibility, PIVOT_HIDE).toInt();
200 
201  settings.endGroup();
202 
203  // pivot visibility
204  switch (pivotVisibility) {
205  case PIVOT_HIDE:
207  break;
208  case PIVOT_SHOW_ON_MOVE:
210  break;
211  case PIVOT_ALWAYS_SHOW:
213  break;
214  }
215 
216  // apply saved parameters
217  SetPerspectiveState(perspectiveView, objectCenteredView);
218  }
219 
220  s_tools.instance->m_deferredPickingTimer.setSingleShot(true);
221  s_tools.instance->m_deferredPickingTimer.setInterval(100);
222 
223  // signal/slot connections
224  connect(s_tools.instance, &ecvDisplayTools::itemPickedFast,
226  Qt::DirectConnection);
227  connect(GetVisualizer3D(),
230 
231  connect(&s_tools.instance->m_scheduleTimer, &QTimer::timeout,
233  connect(&s_tools.instance->m_deferredPickingTimer, &QTimer::timeout,
235 }
236 
238  if (!s_tools.instance) {
239  CVLog::Warning("ecvDisplayTools must be initialized");
240  return nullptr;
241  }
242  return s_tools.instance;
243 }
244 
246  if (s_tools.instance) {
247  s_tools.release();
248  }
249 }
250 
253  if (m_winDBRoot) {
254  delete m_winDBRoot;
255  m_winDBRoot = nullptr;
256  }
257  if (m_rectPickingPoly) {
258  delete m_rectPickingPoly;
259  m_rectPickingPoly = nullptr;
260  }
261  if (m_hotZone) {
262  delete m_hotZone;
263  m_hotZone = nullptr;
264  }
265 }
266 
269  m_timer.elapsed() > m_scheduledFullRedrawTime) {
270  // clean the outdated messages
271  {
272  std::list<MessageToDisplay>::iterator it =
273  m_messagesToDisplay.begin();
274  qint64 currentTime_sec = m_timer.elapsed() / 1000;
275  // CVLog::PrintDebug(QString("[paintGL] Current time:
276  // %1.").arg(currentTime_sec));
277 
278  while (it != m_messagesToDisplay.end()) {
279  // no more valid? we delete the message
280  if (it->messageValidity_sec < currentTime_sec) {
282  it->message));
283  it = m_messagesToDisplay.erase(it);
284  } else {
285  ++it;
286  }
287  }
288  }
289  }
290 }
291 
294  m_scheduleTimer.stop();
295 }
296 
297 void ecvDisplayTools::scheduleFullRedraw(unsigned maxDelay_ms) {
298  m_scheduledFullRedrawTime = m_timer.elapsed() + maxDelay_ms;
299 
300  if (!m_scheduleTimer.isActive()) {
301  m_scheduleTimer.start(500);
302  }
303 }
304 
306  int index,
307  const std::string& id) {
309  m_last_point_index = index;
310  m_last_picked_id = id.c_str();
311 #ifdef QT_DEBUG
312  CVLog::Print(QString("current selected index is %1").arg(index));
313  CVLog::Print(
314  QString("current selected entity id is %1").arg(m_last_picked_id));
315  CVLog::Print(QString("current selected point coord is [%1, %2, %3]")
316  .arg(p.x)
317  .arg(p.y)
318  .arg(p.z));
319 #endif // !QDEBUG
320 
321  if (m_last_picked_id.isEmpty()) {
322  PICKING_MODE pickingMode = PICKING_MODE::ENTITY_PICKING;
323  PickingParameters params(pickingMode, 0, 0, m_pickRadius, m_pickRadius);
324  ProcessPickingResult(params, nullptr, -1);
325  } else {
327  doPicking();
328  }
329  }
330 }
331 
333  // CRITICAL: If a VTK widget was clicked, skip picking to prevent
334  // overriding the widget selection
335  if (m_widgetClicked) {
337  "[ecvDisplayTools::doPicking] Skipping picking because "
338  "VTK widget was clicked");
339  m_widgetClicked = false; // Reset flag after use
340  return;
341  }
342 
343  int x = m_lastMousePos.x();
344  int y = m_lastMousePos.y();
345 
346  if (x < 0 || y < 0) {
347  assert(false);
348  return;
349  }
350 
351  if ((m_pickingMode != NO_PICKING) ||
354  // label selection
355  UpdateActiveItemsList(x, y, false);
356  if (!m_activeItems.empty() && m_activeItems.size() == 1) {
357  ccInteractor* pickedObj = m_activeItems.front();
358  cc2DLabel* label = dynamic_cast<cc2DLabel*>(pickedObj);
359  if (label && !label->isSelected()) {
360  // warning deprecated!
361  emit s_tools.instance->entitySelectionChanged(label);
362  QApplication::processEvents();
363  }
364  }
365  } else {
366  assert(m_activeItems.empty());
367  }
368 
369  if (m_activeItems.empty() && m_pickingMode != NO_PICKING) {
370  // perform standard picking
371  PICKING_MODE pickingMode = m_pickingMode;
372 
373  // shift+Alt = point/triangle picking
374  if (pickingMode == ENTITY_PICKING &&
375  (QApplication::keyboardModifiers() & Qt::AltModifier)) {
376  pickingMode = LABEL_PICKING;
377  } else if (pickingMode == ENTITY_PICKING &&
378  (QApplication::keyboardModifiers() &
379  Qt::ControlModifier)) {
380  pickingMode = POINT_OR_TRIANGLE_PICKING;
381  }
382 
383  PickingParameters params(pickingMode, x, y, m_pickRadius,
384  m_pickRadius);
385  StartPicking(params);
386  }
387  }
388 }
389 
390 void ecvDisplayTools::onWheelEvent(float wheelDelta_deg) {
391  // in perspective mode, wheel event corresponds to 'walking'
393  // to zoom in and out we simply change the fov in bubble-view mode!
396  wheelDelta_deg / 3.6f); // 1 turn = 100 degrees
397  } else {
398  // convert degrees in 'constant' walking speed in ... pixels ;)
399  const double& deg2PixConversion = GetDisplayParameters().zoomSpeed;
400  double delta = deg2PixConversion *
401  static_cast<double>(wheelDelta_deg) *
403 
404  // if we are (clearly) outisde of the displayed objects bounding-box
406  // we go faster if we are far from the entities
407  delta *= 1.0 + std::log(m_cameraToBBCenterDist / m_bbHalfDiag);
408  }
409 
410  // MoveCamera(0.0f, 0.0f,
411  // static_cast<float>(-delta));
412  }
413  } else // ortho. mode
414  {
415  // convert degrees in zoom 'power'
416  static const float c_defaultDeg2Zoom = 20.0f;
417  float zoomFactor = std::pow(1.1f, wheelDelta_deg / c_defaultDeg2Zoom);
418  UpdateZoom(zoomFactor);
419  }
420 
422 }
423 
425  if (s_tools.instance->m_clickableItems.empty()) {
426  return false;
427  }
428 
429  // correction for HD screens
430  const int retinaScale = GetDevicePixelRatio();
431  x *= retinaScale;
432  y *= retinaScale;
433 
435  for (std::vector<ClickableItem>::const_iterator it =
436  s_tools.instance->m_clickableItems.begin();
437  it != s_tools.instance->m_clickableItems.end(); ++it) {
438  if (it->area.contains(x, y)) {
439  clickedItem = it->role;
440  break;
441  }
442  }
443 
444  switch (clickedItem) {
445  case ClickableItem::NO_ROLE: {
446  // nothing to do
447  } break;
448 
450  SetPointSize(s_tools.instance->m_viewportParams.defaultPointSize +
451  1.0f);
452  SetRedrawRecursive(false);
453  RedrawDisplay();
454  }
455  return true;
456 
458  SetPointSize(s_tools.instance->m_viewportParams.defaultPointSize -
459  1.0f);
460  SetRedrawRecursive(false);
461  RedrawDisplay();
462  }
463  return true;
464 
466  SetLineWidth(s_tools.instance->m_viewportParams.defaultLineWidth +
467  1.0f);
468  SetRedrawRecursive(false);
469  RedrawDisplay();
470  }
471  return true;
472 
474  SetLineWidth(s_tools.instance->m_viewportParams.defaultLineWidth -
475  1.0f);
476  SetRedrawRecursive(false);
477  RedrawDisplay();
478  }
479  return true;
480 
482  SetBubbleViewMode(false);
483  RedrawDisplay();
484  }
485  return true;
486 
488  if (s_tools.instance->m_win) {
489  emit s_tools.instance->exclusiveFullScreenToggled(false);
490  }
491  }
492  return true;
493 
494  default: {
495  // unhandled item?!
496  assert(false);
497  } break;
498  }
499 
500  return false;
501 }
502 
503 void ecvDisplayTools::SetPointSize(float size, bool silent, int viewport) {
504  float newSize =
505  std::max(std::min(size, MAX_POINT_SIZE_F), MIN_POINT_SIZE_F);
506  if (!silent) {
507  CVLog::Print(QString("New point size: %1").arg(newSize));
508  }
509 
510  if (s_tools.instance->m_viewportParams.defaultPointSize != newSize) {
511  s_tools.instance->m_viewportParams.defaultPointSize = newSize;
512  SetPointSizeRecursive(static_cast<int>(newSize));
513 
514  if (!silent) {
516  QString("New default point size: %1").arg(newSize),
517  ecvDisplayTools::LOWER_LEFT_MESSAGE, // DGM HACK: we cheat
518  // and use the same
519  // 'slot' as the
520  // window size
521  false, 2, SCREEN_SIZE_MESSAGE);
522  }
523  }
524 }
525 
527  // we draw 3D entities
528  if (s_tools.instance->m_globalDBRoot) {
529  s_tools.instance->m_globalDBRoot->setPointSizeRecursive(size);
530  }
531 
532  if (s_tools.instance->m_winDBRoot) {
533  s_tools.instance->m_winDBRoot->setPointSizeRecursive(size);
534  }
535 }
536 
537 void ecvDisplayTools::SetLineWidth(float width, bool silent, int viewport) {
538  float newWidth =
539  std::max(std::min(width, MAX_LINE_WIDTH_F), MIN_LINE_WIDTH_F);
540  if (!silent) {
541  CVLog::Print(QString("New line with: %1").arg(newWidth));
542  }
543 
544  if (s_tools.instance->m_viewportParams.defaultLineWidth != newWidth) {
545  s_tools.instance->m_viewportParams.defaultLineWidth = newWidth;
546  SetLineWithRecursive(newWidth);
547  if (!silent) {
549  QString("New default line width: %1").arg(newWidth),
550  ecvDisplayTools::LOWER_LEFT_MESSAGE, // DGM HACK: we cheat
551  // and use the same
552  // 'slot' as the
553  // window size
554  false, 2, SCREEN_SIZE_MESSAGE);
555  }
556  }
557 }
558 
560  // we draw 3D entities
561  if (s_tools.instance->m_globalDBRoot) {
562  s_tools.instance->m_globalDBRoot->setLineWidthRecursive(with);
563  }
564 
565  if (s_tools.instance->m_winDBRoot) {
566  s_tools.instance->m_winDBRoot->setLineWidthRecursive(with);
567  }
568 }
569 
571  // correction for HD screens
572  const int retinaScale = GetDevicePixelRatio();
573  params.centerX *= retinaScale;
574  params.centerY *= retinaScale;
575 
576  if (!s_tools.instance->m_globalDBRoot && !s_tools.instance->m_winDBRoot) {
577  // we must always emit a signal!
578  ProcessPickingResult(params, nullptr, -1);
579  return;
580  }
581 
582  if (params.mode == POINT_OR_TRIANGLE_PICKING ||
583  params.mode == POINT_PICKING || params.mode == TRIANGLE_PICKING ||
584  params.mode == LABEL_PICKING // = spawn a label on the clicked point or
585  // triangle
586  ) {
587  // CPU-based point picking
589  } else {
590  StartOpenGLPicking(params);
591  }
592 }
593 
595  const PickingParameters& params,
596  ccHObject* pickedEntity,
597  int pickedItemIndex,
598  const CCVector3* nearestPoint /*=0*/,
599  const std::unordered_set<int>* selectedIDs /*=0*/) {
600  // standard "entity" picking
601  if (params.mode == ENTITY_PICKING) {
602  emit s_tools.instance->entitySelectionChanged(pickedEntity);
603  }
604  // rectangular "entity" picking
605  else if (params.mode == ENTITY_RECT_PICKING) {
606  if (selectedIDs)
607  emit s_tools.instance->entitiesSelectionChanged(*selectedIDs);
608  else
609  assert(false);
610  }
611  // 3D point or triangle picking
612  else if (params.mode == POINT_PICKING || params.mode == TRIANGLE_PICKING ||
613  params.mode == POINT_OR_TRIANGLE_PICKING) {
614  assert(pickedEntity == nullptr || pickedItemIndex >= 0);
615  assert(nearestPoint);
616 
617  emit s_tools.instance->itemPicked(
618  pickedEntity, static_cast<unsigned>(pickedItemIndex),
619  params.centerX, params.centerY, *nearestPoint);
620  }
621  // fast picking (labels, interactors, etc.)
622  else if (params.mode == FAST_PICKING) {
623  emit s_tools.instance->itemPickedFast(pickedEntity, pickedItemIndex,
624  params.centerX, params.centerY);
625  } else if (params.mode == LABEL_PICKING) {
626  if (s_tools.instance->m_globalDBRoot && pickedEntity &&
627  pickedItemIndex >= 0) {
628  // qint64 stopTime = m_timer.nsecsElapsed();
629  // CVLog::Print(QString("[Picking] entity ID %1 - item #%2 (time: %3
630  // ms)").arg(selectedID).arg(pickedItemIndex).arg((stopTime-startTime)
631  // / 1.0e6));
632 
633  // auto spawn the right label
634  cc2DLabel* label = nullptr;
635  if (pickedEntity->isKindOf(CV_TYPES::POINT_CLOUD)) {
636  label = new cc2DLabel();
637  label->addPickedPoint(
639  pickedItemIndex);
640  pickedEntity->addChild(label);
641  } else if (pickedEntity->isKindOf(CV_TYPES::MESH)) {
642  label = new cc2DLabel();
643  ccGenericMesh* mesh =
644  ccHObjectCaster::ToGenericMesh(pickedEntity);
645  ccGenericPointCloud* cloud = mesh->getAssociatedCloud();
646  assert(cloud);
647  cloudViewer::VerticesIndexes* vertexIndexes =
648  mesh->getTriangleVertIndexes(pickedItemIndex);
649  label->addPickedPoint(cloud, vertexIndexes->i1);
650  label->addPickedPoint(cloud, vertexIndexes->i2);
651  label->addPickedPoint(cloud, vertexIndexes->i3);
652  cloud->addChild(label);
653  if (!cloud->isEnabled()) {
654  cloud->setVisible(false);
655  cloud->setEnabled(true);
656  }
657  }
658 
659  if (label) {
660  label->setVisible(true);
661  label->setPosition(
662  static_cast<float>(params.centerX + 20) /
663  s_tools.instance->m_glViewport.width(),
664  static_cast<float>(params.centerY + 20) /
665  s_tools.instance->m_glViewport.height());
666  emit s_tools.instance->newLabel(static_cast<ccHObject*>(label));
667  QApplication::processEvents();
668  }
669  }
670  }
671 }
672 
673 void ecvDisplayTools::SetZNearCoef(double coef) {
674  if (coef <= 0.0 || coef >= 1.0) {
675  CVLog::Warning("[ecvDisplayTools::setZNearCoef] Invalid coef. value!");
676  return;
677  }
678 
679  if (s_tools.instance->m_viewportParams.zNearCoef != coef) {
680  // update param
681  s_tools.instance->m_viewportParams.zNearCoef = coef;
682  // and camera state (if perspective view is 'on')
683  if (s_tools.instance->m_viewportParams.perspectiveView) {
684  // DGM: we update the projection matrix directly so as to get an
685  // up-to-date estimation of zNear
687 
688  SetCameraClip(s_tools.instance->m_viewportParams.zNear,
689  s_tools.instance->m_viewportParams.zFar);
690 
692 
694  QString("Near clipping = %1% of max depth (= %2)")
695  .arg(s_tools.instance->m_viewportParams.zNearCoef *
696  100.0,
697  0, 'f', 1)
698  .arg(s_tools.instance->m_viewportParams.zNear),
699  ecvDisplayTools::LOWER_LEFT_MESSAGE, // DGM HACK: we cheat
700  // and use the same
701  // 'slot' as the
702  // window size
703  false, 2, SCREEN_SIZE_MESSAGE);
704  }
705 
706  emit s_tools.instance->zNearCoefChanged(coef);
707  emit s_tools.instance->cameraParamChanged();
708  }
709 }
710 
711 // DGM: WARNING: OpenGL picking with the picking buffer is depreacted.
712 // We need to get rid of this code or change it to color-based selection...
714  if (!params.pickInLocalDB && !params.pickInSceneDB) {
715  assert(false);
716  return;
717  }
718 
719  // setup rendering context
720  unsigned short flags = CC_DRAW_FOREGROUND;
721 
722  switch (params.mode) {
723  case FAST_PICKING:
724  flags |= CC_FAST_ENTITY_PICKING;
725  case ENTITY_PICKING:
726  case ENTITY_RECT_PICKING:
727  flags |= CC_ENTITY_PICKING;
728  break;
729  default:
730  // unhandled mode?!
731  assert(false);
732  // we must always emit a signal!
733  ProcessPickingResult(params, nullptr, -1);
734  return;
735  }
736 
737  // OpenGL picking
738  assert(!s_tools.instance->m_captureMode.enabled);
739 
740  // process hits
741  std::unordered_set<int> selectedIDs;
742  int pickedItemIndex = -1;
743  int selectedID = -1;
744  ccHObject* pickedEntity = nullptr;
745 
746  CCVector3 P(0, 0, 0);
747  CCVector3* pickedPoint = nullptr;
748 
749  if (s_tools.instance->m_last_point_index >= 0) {
750  pickedEntity = GetPickedEntity(params);
751  if (pickedEntity) {
752  selectedID = pickedEntity->getUniqueID();
753  selectedIDs.insert(selectedID);
754  pickedItemIndex = s_tools.instance->m_last_point_index;
755  }
756  }
757 
758  if (pickedEntity && pickedItemIndex >= 0 &&
759  pickedEntity->isKindOf(CV_TYPES::POINT_CLOUD)) {
760  ccGenericPointCloud* tempEntity =
762  int pNum = static_cast<int>(tempEntity->size());
763  if (pickedItemIndex >= pNum) {
764  P = s_tools.instance->m_last_picked_point;
766  QString("[ecvDisplayTools::StartOpenGLPicking] Picking "
767  "Error, %1 is more than picked entity size %2")
768  .arg(pickedItemIndex)
769  .arg(tempEntity->size()));
770  pickedItemIndex = pNum - 1;
771  } else {
772  P = *(static_cast<ccGenericPointCloud*>(pickedEntity)
773  ->getPoint(pickedItemIndex));
774  // check selected point
775  CCVector3 temp = P - s_tools.instance->m_last_picked_point;
776  if (temp.norm() > 1) {
777  ProcessPickingResult(params, nullptr, -1);
778 #ifdef QT_DEBUG
780  QString("[ecvDisplayTools::StartOpenGLPicking] droped "
781  "selected point coord is [%1, %2, %3]")
782  .arg(P.x)
783  .arg(P.y)
784  .arg(P.z));
785 #endif // QT_DEBUG
786  return;
787  }
788  }
789 
790  pickedPoint = &P;
791  }
792 
793  // we must always emit a signal!
794  ProcessPickingResult(params, pickedEntity, pickedItemIndex, pickedPoint,
795  &selectedIDs);
796 }
797 
799  const PickingParameters& params) {
800  // qint64 t0 = m_timer.elapsed();
801  CCVector2d clickedPos(
802  params.centerX,
803  s_tools.instance->m_glViewport.height() - 1 - params.centerY);
804 
805  ccHObject* nearestEntity = nullptr;
806  int nearestElementIndex = -1;
807  double nearestElementSquareDist = -1.0;
808  CCVector3 nearestPoint(0, 0, 0);
809  static const unsigned MIN_POINTS_FOR_OCTREE_COMPUTATION = 128;
810 
812  autoComputeOctreeThisSession = ecvGui::ParamStruct::ASK_USER;
813  bool autoComputeOctree = false;
814  bool firstCloudWithoutOctree = true;
815 
816  ccGLCameraParameters camera;
817  GetGLCameraParameters(camera);
818 
820  int pickedIndex = -1;
821  ccHObject* pickedEntity = nullptr;
822  if (s_tools.instance->m_last_point_index >= 0) {
823  pickedIndex = s_tools.instance->m_last_point_index;
824  pickedEntity = GetPickedEntity(params);
825  }
826 
827  if (pickedEntity && pickedIndex >= 0) {
828  ccHObject* ent = nullptr;
829  if (pickedEntity->isKindOf(CV_TYPES::POINT_CLOUD)) {
830  ent = pickedEntity;
831  } else if (pickedEntity->isKindOf(CV_TYPES::MESH) &&
832  !pickedEntity->isA(CV_TYPES::MESH_GROUP)) {
833  ccGenericMesh* mesh =
834  ccHObjectCaster::ToGenericMesh(pickedEntity);
835  ent = mesh->getAssociatedCloud();
836  } else {
837  return;
838  }
839 
840  ccGenericPointCloud* tempEntity =
842  nearestElementIndex = pickedIndex;
843  int pNum = static_cast<int>(tempEntity->size());
844  if (pickedIndex >= pNum) {
845  nearestPoint = s_tools.instance->m_last_picked_point;
847  QString("[ecvDisplayTools::StartCPUBasedPointPicking] "
848  "Picking Error, %1 is more than picked entity "
849  "size %2")
850  .arg(pickedIndex)
851  .arg(tempEntity->size()));
852  nearestElementIndex = pNum;
853  } else {
854  nearestPoint = *(tempEntity->getPoint(pickedIndex));
855  // check selected point
856  CCVector3 temp =
857  nearestPoint - s_tools.instance->m_last_picked_point;
858  if (temp.norm() > 1) {
859  ProcessPickingResult(params, nullptr, -1);
860 #ifdef QT_DEBUG
862  QString("[ecvDisplayTools::"
863  "StartCPUBasedPointPicking] droped "
864  "selected point coord is [%1, %2, %3]")
865  .arg(nearestPoint.x)
866  .arg(nearestPoint.y)
867  .arg(nearestPoint.z));
868 #endif // QT_DEBUG
869  return;
870  }
871  }
872 
873  nearestEntity = pickedEntity;
874  }
875  } else {
876  try {
877  ccHObject::Container toProcess;
878  if (s_tools.instance->m_globalDBRoot)
879  toProcess.push_back(s_tools.instance->m_globalDBRoot);
880  if (s_tools.instance->m_winDBRoot)
881  toProcess.push_back(s_tools.instance->m_winDBRoot);
882 
883  while (!toProcess.empty()) {
884  // get next item
885  ccHObject* ent = toProcess.back();
886  toProcess.pop_back();
887 
888  if (!ent->isEnabled()) continue;
889 
890  bool ignoreSubmeshes = false;
891 
892  // we look for point cloud displayed in this window
893  if (ent->isKindOf(CV_TYPES::POINT_CLOUD)) {
894  ccGenericPointCloud* cloud =
895  static_cast<ccGenericPointCloud*>(ent);
896 
897  if (firstCloudWithoutOctree && !cloud->getOctree() &&
898  cloud->size() >
899  MIN_POINTS_FOR_OCTREE_COMPUTATION) // no need
900  // to use
901  // the
902  // octree
903  // for a few
904  // points!
905  {
906  // can we compute an octree for picking?
909  if (behavior == ecvGui::ParamStruct::ASK_USER) {
910  // we use the persistent parameter for this session
911  behavior = autoComputeOctreeThisSession;
912  }
913 
914  switch (behavior) {
916  autoComputeOctree = true;
917  break;
918 
920  QMessageBox question(
921  QMessageBox::Question,
922  "Picking acceleration",
923  "Automatically compute octree(s) to "
924  "accelerate the picking "
925  "process?\n(this behavior can be "
926  "changed later in the Display "
927  "Settings)",
928  QMessageBox::NoButton,
929  GetCurrentScreen());
930 
931  QPushButton* yes = new QPushButton("Yes");
932  question.addButton(yes,
933  QMessageBox::AcceptRole);
934  QPushButton* no = new QPushButton("No");
935  question.addButton(no, QMessageBox::RejectRole);
936  QPushButton* always = new QPushButton("Always");
937  question.addButton(always,
938  QMessageBox::AcceptRole);
939  QPushButton* never = new QPushButton("Never");
940  question.addButton(never,
941  QMessageBox::RejectRole);
942 
943  question.exec();
944  QAbstractButton* clickedButton =
945  question.clickedButton();
946  if (clickedButton == yes) {
947  autoComputeOctree = true;
948  autoComputeOctreeThisSession =
950  } else if (clickedButton == no) {
952  "now only support octree picking, "
953  "please don't select no!");
954  continue;
955  autoComputeOctree = false;
956  autoComputeOctreeThisSession =
958  } else if (clickedButton == always ||
959  clickedButton == never) {
960  autoComputeOctree =
961  (clickedButton == always);
962  // update the global application parameters
963  ecvGui::ParamStruct params =
965  params.autoComputeOctree =
966  autoComputeOctree
968  ALWAYS
970  NEVER;
971  ecvGui::Set(params);
972  params.toPersistentSettings();
973  }
974  } break;
975 
977  autoComputeOctree = false;
978  break;
979  }
980 
981  firstCloudWithoutOctree = false;
982  }
983 
984  int nearestPointIndex = -1;
985  double nearestSquareDist = 0.0;
986  if (cloud->pointPicking(
987  clickedPos, camera, nearestPointIndex,
988  nearestSquareDist, params.pickWidth,
989  params.pickHeight,
990  autoComputeOctree &&
991  cloud->size() >
992  MIN_POINTS_FOR_OCTREE_COMPUTATION)) {
993  if (nearestElementIndex < 0 ||
994  (nearestPointIndex >= 0 &&
995  nearestSquareDist < nearestElementSquareDist)) {
996  nearestElementSquareDist = nearestSquareDist;
997  nearestElementIndex = nearestPointIndex;
998  nearestPoint =
999  *(cloud->getPoint(nearestPointIndex));
1000  nearestEntity = cloud;
1001  }
1002  }
1003  } else if (ent->isKindOf(CV_TYPES::MESH) &&
1004  !ent->isA(CV_TYPES::MESH_GROUP) // we don't need to
1005  // process mesh
1006  // groups as their
1007  // children will be
1008  // processed later
1009  &&
1010  !ent->isA(CV_TYPES::COORDINATESYSTEM) // we ignore
1011  // coordinate
1012  // system
1013  // entities
1014  ) {
1015  ignoreSubmeshes = true;
1016 
1017  ccGenericMesh* mesh = static_cast<ccGenericMesh*>(ent);
1018  if (mesh->isShownAsWire()) {
1019  // skip meshes that are displayed in wireframe mode
1020  continue;
1021  }
1022 
1023  int nearestTriIndex = -1;
1024  double nearestSquareDist = 0.0;
1025  CCVector3d P;
1026  if (mesh->trianglePicking(clickedPos, camera,
1027  nearestTriIndex,
1028  nearestSquareDist, P)) {
1029  if (nearestElementIndex < 0 ||
1030  (nearestTriIndex >= 0 &&
1031  nearestSquareDist < nearestElementSquareDist)) {
1032  nearestElementSquareDist = nearestSquareDist;
1033  nearestElementIndex = nearestTriIndex;
1034  nearestPoint = CCVector3::fromArray(P.u);
1035  nearestEntity = mesh;
1036  }
1037  }
1038  } else if (params.mode ==
1039  PICKING_MODE::
1041  ent->isA(CV_TYPES::LABEL_2D)) {
1042  cc2DLabel* label = static_cast<cc2DLabel*>(ent);
1043 
1044  int nearestPointIndex = -1;
1045  double nearestSquareDist = 0.0;
1046 
1047  if (label->pointPicking(clickedPos, camera,
1048  nearestPointIndex,
1049  nearestSquareDist)) {
1050  if (nearestElementIndex < 0 ||
1051  (nearestPointIndex >= 0 &&
1052  nearestSquareDist < nearestElementSquareDist)) {
1053  nearestElementSquareDist = nearestSquareDist;
1054  assert(nearestPointIndex <
1055  static_cast<int>(label->size()));
1056  nearestElementIndex = nearestPointIndex;
1057  nearestPoint =
1058  label->getPickedPoint(nearestPointIndex)
1059  .getPointPosition();
1060  nearestEntity = label;
1061  }
1062  }
1063  } else if (ent->isKindOf(CV_TYPES::SENSOR)) {
1064  // only activated when ctrl and mouse pressed!
1065  if (params.mode != POINT_OR_TRIANGLE_PICKING) {
1066  continue;
1067  }
1068 
1069  if (ent->isA(CV_TYPES::CAMERA_SENSOR)) {
1070  ignoreSubmeshes = true;
1071 
1072  ccCameraSensor* cameraSensor =
1073  static_cast<ccCameraSensor*>(ent);
1074  if (!cameraSensor &&
1075  cameraSensor->getNearPlane().IsEmpty()) {
1076  // skip meshes that are displayed in wireframe mode
1077  continue;
1078  }
1079 
1080  QString id = ecvDisplayTools::PickObject(clickedPos.x,
1081  clickedPos.y);
1082 
1083  if (id.toInt() != -1 &&
1084  static_cast<int>(cameraSensor->getUniqueID()) ==
1085  id.toInt()) {
1086  nearestElementIndex = id.toInt();
1087  nearestPoint = CCVector3();
1088  nearestEntity = cameraSensor;
1089  break;
1090  }
1091  }
1092  }
1093 
1094  // add children
1095  for (unsigned i = 0; i < ent->getChildrenNumber(); ++i) {
1096  // we ignore the sub-meshes of the current (mesh) entity
1097  // as their content is the same!
1098  if (ignoreSubmeshes &&
1099  ent->getChild(i)->isKindOf(CV_TYPES::SUB_MESH) &&
1100  static_cast<ccSubMesh*>(ent)->getAssociatedMesh() ==
1101  ent) {
1102  continue;
1103  }
1104 
1105  toProcess.push_back(ent->getChild(i));
1106  }
1107  }
1108  } catch (const std::bad_alloc&) {
1109  // not enough memory
1110  CVLog::Warning("[Picking][CPU] Not enough memory!");
1111  }
1112  }
1113  // qint64 dt = m_timer.elapsed() - t0;
1114  // CVLog::Print(QString("[Picking][CPU] Time: %1 ms").arg(dt));
1115 
1117  s_tools.instance->m_last_point_index = nearestElementIndex;
1118  s_tools.instance->m_last_picked_point = nearestPoint;
1119  if (nearestEntity) {
1120  s_tools.instance->m_last_picked_id = nearestEntity->getViewId();
1121  }
1122  }
1123 
1124  // we must always emit a signal!
1125  ProcessPickingResult(params, nearestEntity, nearestElementIndex,
1126  &nearestPoint);
1127 }
1128 
1130  if (s_tools.instance->m_last_picked_id.isEmpty()) return nullptr;
1131 
1132  ccHObject* pickedEntity = nullptr;
1133  unsigned int selectedID = s_tools.instance->m_last_picked_id.toUInt();
1134  if (params.pickInSceneDB && s_tools.instance->m_globalDBRoot) {
1135  pickedEntity = s_tools.instance->m_globalDBRoot->find(selectedID);
1136  }
1137  if (!pickedEntity && params.pickInLocalDB &&
1138  s_tools.instance->m_winDBRoot) {
1139  pickedEntity = s_tools.instance->m_winDBRoot->find(selectedID);
1140  }
1141 
1142  return pickedEntity;
1143 }
1144 
1146  return QPointF(x - Width() / 2,
1147  Height() / 2 - y) /* * GetDevicePixelRatio()*/;
1148 }
1149 
1151  CCVector3d p = CCVector3d(x * 1.0, y * 1.0, z * 1.0);
1152  ToVtkCoordinates(p);
1153  return p;
1154 }
1155 
1157  sP.y = Height() - sP.y; // for vtk coordinates
1158  sP *= GetDevicePixelRatio();
1159 }
1160 
1162  sP.y = Height() - sP.y; // for vtk coordinates
1163  sP *= GetDevicePixelRatio();
1164 }
1165 
1167  s_tools.instance->m_pivotVisibility = vis;
1168 
1169  if (vis == PivotVisibility::PIVOT_HIDE) {
1170  SetPivotVisibility(false);
1171  } else {
1172  SetPivotVisibility(true);
1173  }
1174 
1175  UpdateScreen();
1176 
1177  // auto-save last pivot visibility settings
1178  {
1179  QSettings settings;
1180  settings.beginGroup(c_ps_groupName);
1181  settings.setValue(c_ps_pivotVisibility, vis);
1182  settings.endGroup();
1183  }
1184 }
1185 
1186 void ecvDisplayTools::ResizeGL(int w, int h) {
1187  // update OpenGL viewport
1188  SetGLViewport(0, 0, w, h);
1189 
1191  Deprecate3DLayer();
1192 
1193  if (s_tools.instance->m_hotZone) {
1194  s_tools.instance->m_hotZone->topCorner = QPoint(0, 0);
1195  }
1196 
1197  DisplayNewMessage(QString("New size = %1 * %2 (px)")
1198  .arg(s_tools.instance->m_glViewport.width())
1199  .arg(s_tools.instance->m_glViewport.height()),
1201 }
1202 
1203 void ecvDisplayTools::MoveCamera(float dx, float dy, float dz) {
1204  if (dx != 0.0f || dy != 0.0f) // camera movement? (dz doesn't count as it
1205  // only corresponds to a zoom)
1206  {
1207  // feedback for echo mode
1208  emit s_tools.instance->cameraDisplaced(dx, dy);
1209  }
1210 
1211  // current X, Y and Z viewing directions
1212  // correspond to the 'model view' matrix
1213  // lines.
1214  CCVector3d V(dx, dy, dz);
1215  if (!s_tools.instance->m_viewportParams.objectCenteredView) {
1216  s_tools.instance->m_viewportParams.viewMat.transposed().applyRotation(
1217  V);
1218  }
1219 
1220  SetCameraPos(s_tools.instance->m_viewportParams.getCameraCenter() + V);
1221 }
1222 
1224  int x, int y, bool extendToSelectedLabels /*=false*/) {
1225  s_tools.instance->m_activeItems.clear();
1226 
1227  PickingParameters params(FAST_PICKING, x, y, 2, 2);
1228 
1229  StartPicking(params);
1230 
1231  if (s_tools.instance->m_activeItems.size() == 1) {
1232  ccInteractor* pickedObj = s_tools.instance->m_activeItems.front();
1233  cc2DLabel* label = dynamic_cast<cc2DLabel*>(pickedObj);
1234  if (label) {
1235  if (!label->isSelected() || !extendToSelectedLabels) {
1236  // select it?
1237  // emit entitySelectionChanged(label);
1238  // QApplication::processEvents();
1239  } else {
1240  // we get the other selected labels as well!
1241  ccHObject::Container labels;
1242  if (s_tools.instance->m_globalDBRoot)
1243  s_tools.instance->m_globalDBRoot->filterChildren(
1244  labels, true, CV_TYPES::LABEL_2D);
1245  if (s_tools.instance->m_winDBRoot)
1246  s_tools.instance->m_winDBRoot->filterChildren(
1247  labels, true, CV_TYPES::LABEL_2D);
1248 
1249  for (auto& label : labels) {
1250  if (label->isA(CV_TYPES::LABEL_2D) &&
1251  label->isVisible()) // Warning: cc2DViewportLabel is
1252  // also a kind of
1253  // 'CV_TYPES::LABEL_2D'!
1254  {
1255  cc2DLabel* l = static_cast<cc2DLabel*>(label);
1256  if (l != label && l->isSelected()) {
1257  s_tools.instance->m_activeItems.push_back(l);
1258  }
1259  }
1260  }
1261  }
1262  }
1263  }
1264 }
1265 
1267  int pickedItemIndex,
1268  int x,
1269  int y) {
1270  if (pickedEntity) {
1271  if (pickedEntity->isA(CV_TYPES::LABEL_2D)) {
1272  cc2DLabel* label = static_cast<cc2DLabel*>(pickedEntity);
1273  m_activeItems.push_back(label);
1274  } else if (pickedEntity->isA(CV_TYPES::CLIPPING_BOX)) {
1275  ccClipBox* cbox = static_cast<ccClipBox*>(pickedEntity);
1276  cbox->setActiveComponent(pickedItemIndex);
1277  cbox->setClickedPoint(x, y, Width(), Height(),
1279 
1280  m_activeItems.push_back(cbox);
1281  }
1282  }
1283 
1284  emit fastPickingFinished();
1285 }
1286 
1288 
1290  double xc = static_cast<double>(Width() / 2);
1291  double yc = static_cast<double>(
1292  Height() / 2); // DGM FIME: is it scaled coordinates or not?!
1293 
1294  CCVector3d Q2D;
1295  if (s_tools.instance->m_viewportParams.objectCenteredView) {
1296  // project the current pivot point on screen
1297  ccGLCameraParameters camera;
1298  GetGLCameraParameters(camera);
1299 
1300  if (!camera.project(s_tools.instance->m_viewportParams.getPivotPoint(),
1301  Q2D)) {
1302  // arbitrary direction
1303  return CCVector3d(0, 0, 1);
1304  }
1305 
1306  // we set the virtual rotation pivot closer to the actual one (but we
1307  // always stay in the central part of the screen!)
1308  Q2D.x = std::min(Q2D.x, 3.0 * Width() / 4.0);
1309  Q2D.x = std::max(Q2D.x, Width() / 4.0);
1310 
1311  Q2D.y = std::min(Q2D.y, 3.0 * Height() / 4.0);
1312  Q2D.y = std::max(Q2D.y, Height() / 4.0);
1313  } else {
1314  Q2D.x = xc;
1315  Q2D.y = yc;
1316  }
1317 
1318  // invert y
1319  y = Height() - 1 - y;
1320 
1321  CCVector3d v(x - Q2D.x, y - Q2D.y, 0.0);
1322 
1323  v.x = std::max(std::min(v.x / xc, 1.0), -1.0);
1324  v.y = std::max(std::min(v.y / yc, 1.0), -1.0);
1325 
1326  // square 'radius'
1327  double d2 = v.x * v.x + v.y * v.y;
1328 
1329  // projection on the unit sphere
1330  if (d2 > 1) {
1331  double d = std::sqrt(d2);
1332  v.x /= d;
1333  v.y /= d;
1334  } else {
1335  v.z = std::sqrt(1.0 - d2);
1336  }
1337 
1338  return v;
1339 }
1340 
1343  viewParams.viewMat = rotMat * viewParams.viewMat;
1344 
1345  // pos
1346  CCVector3d camC = viewParams.viewMat.getTranslationAsVec3D();
1347  viewParams.setCameraCenter(camC);
1348 
1349  // up
1350  CCVector3d upDir = viewParams.viewMat.getColumnAsVec3D(1);
1351  upDir.normalize();
1352  viewParams.up = upDir;
1353 
1354  // focal
1355  CCVector3d viewDir = viewParams.viewMat.getColumnAsVec3D(2);
1356  viewParams.focal = camC - viewDir;
1357  viewParams.setPivotPoint(viewParams.focal, true);
1358 
1360 
1361  // we emit the 'baseViewMatChanged' signal
1362  emit s_tools.instance->baseViewMatChanged(
1363  s_tools.instance->m_viewportParams.viewMat);
1364 }
1365 
1367  CCVector3d eye(0, 0, 0);
1368  CCVector3d center(0, 0, 0);
1369  CCVector3d top(0, 0, 0);
1370 
1371  // we look at (0,0,0) by default
1372  switch (orientation) {
1373  case CC_TOP_VIEW:
1374  eye.z = 1.0;
1375  top.y = 1.0;
1376  break;
1377  case CC_BOTTOM_VIEW:
1378  eye.z = -1.0;
1379  top.y = 1.0;
1380  break;
1381  case CC_FRONT_VIEW:
1382  eye.y = -1.0;
1383  top.z = 1.0;
1384  break;
1385  case CC_BACK_VIEW:
1386  eye.y = 1.0;
1387  top.z = 1.0;
1388  break;
1389  case CC_LEFT_VIEW:
1390  eye.x = -1.0;
1391  top.z = 1.0;
1392  break;
1393  case CC_RIGHT_VIEW:
1394  eye.x = 1.0;
1395  top.z = 1.0;
1396  break;
1397  case CC_ISO_VIEW_1:
1398  eye.x = -1.0;
1399  eye.y = -1.0;
1400  eye.z = 1.0;
1401  top.x = 1.0;
1402  top.y = 1.0;
1403  top.z = 1.0;
1404  break;
1405  case CC_ISO_VIEW_2:
1406  eye.x = 1.0;
1407  eye.y = 1.0;
1408  eye.z = 1.0;
1409  top.x = -1.0;
1410  top.y = -1.0;
1411  top.z = 1.0;
1412  break;
1413  }
1414 
1415  return ccGLMatrixd::FromViewDirAndUpDir(center - eye, top);
1416 }
1417 
1419  switch (orientation) {
1420  case CC_TOP_VIEW:
1421  SetCameraPosition(0, 0, 1, 0, 0, 0, 0, 1, 0);
1422  UpdateConstellationCenterAndZoom(bbox, false);
1423  break;
1424  case CC_BOTTOM_VIEW:
1425  SetCameraPosition(0, 0, -1, 0, 0, 0, 0, 1, 0);
1426  UpdateConstellationCenterAndZoom(bbox, false);
1427  break;
1428  case CC_FRONT_VIEW:
1429  SetCameraPosition(0, 1, 0, 0, 0, 0, 0, 0, 1);
1430  UpdateConstellationCenterAndZoom(bbox, false);
1431  break;
1432  case CC_BACK_VIEW:
1433  SetCameraPosition(0, -1, 0, 0, 0, 0, 0, 0, 1);
1434  UpdateConstellationCenterAndZoom(bbox, false);
1435  break;
1436  case CC_LEFT_VIEW:
1437  SetCameraPosition(-1, 0, 0, 0, 0, 0, 0, 0, 1);
1438  UpdateConstellationCenterAndZoom(bbox, false);
1439  break;
1440  case CC_RIGHT_VIEW:
1441  SetCameraPosition(1.0, 0.0, 0, 0, 0, 0, 0, 0, 1);
1442  UpdateConstellationCenterAndZoom(bbox, false);
1443  break;
1444  case CC_ISO_VIEW_1:
1445  SetCameraPosition(-1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
1446  UpdateConstellationCenterAndZoom(bbox, false);
1447  break;
1448  case CC_ISO_VIEW_2:
1449  SetCameraPosition(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, -1.0, -1.0, 1.0);
1450  UpdateConstellationCenterAndZoom(bbox, false);
1451  break;
1452  default:
1453  break;
1454  }
1455 }
1456 
1458  bool forceRedraw /*=false*/) {
1459  // may be useless
1460  bool wasViewerBased =
1461  !s_tools.instance->m_viewportParams.objectCenteredView;
1462  if (wasViewerBased) {
1463  SetPerspectiveState(s_tools.instance->m_viewportParams.perspectiveView,
1464  true);
1465  }
1466  s_tools.instance->m_viewportParams.viewMat = GenerateViewMat(orientation);
1467  if (wasViewerBased) {
1468  SetPerspectiveState(s_tools.instance->m_viewportParams.perspectiveView,
1469  false);
1470  }
1471 
1472  emit s_tools.instance->baseViewMatChanged(
1473  s_tools.instance->m_viewportParams.viewMat);
1474  emit s_tools.instance->cameraParamChanged();
1475  // may be useless
1476 
1477  // Get current camera parameters to preserve zoom/distance
1478  double currentPos[3], currentFocal[3];
1479  GetCameraPos(currentPos);
1480  GetCameraFocal(currentFocal);
1481 
1482  CCVector3d currentCameraPos(currentPos[0], currentPos[1], currentPos[2]);
1483  CCVector3d currentFocalPoint(currentFocal[0], currentFocal[1],
1484  currentFocal[2]);
1485 
1486  // Calculate current distance from camera to focal point (this represents
1487  // the zoom level)
1488  CCVector3d currentViewDir = currentFocalPoint - currentCameraPos;
1489  double currentDistance = currentViewDir.norm();
1490 
1491  // If distance is too small or invalid, use a default distance
1492  if (currentDistance < 1e-6) {
1493  currentDistance = 1.0;
1494  }
1495 
1496  // Generate view direction and up vector for the new orientation
1497  CCVector3d eye(0, 0, 0);
1498  CCVector3d center(0, 0, 0);
1499  CCVector3d top(0, 0, 0);
1500 
1501  switch (orientation) {
1502  case CC_TOP_VIEW:
1503  eye.z = 1.0;
1504  top.y = 1.0;
1505  break;
1506  case CC_BOTTOM_VIEW:
1507  eye.z = -1.0;
1508  top.y = 1.0;
1509  break;
1510  case CC_FRONT_VIEW:
1511  eye.y = -1.0;
1512  top.z = 1.0;
1513  break;
1514  case CC_BACK_VIEW:
1515  eye.y = 1.0;
1516  top.z = 1.0;
1517  break;
1518  case CC_LEFT_VIEW:
1519  eye.x = -1.0;
1520  top.z = 1.0;
1521  break;
1522  case CC_RIGHT_VIEW:
1523  eye.x = 1.0;
1524  top.z = 1.0;
1525  break;
1526  case CC_ISO_VIEW_1:
1527  eye.x = -1.0;
1528  eye.y = -1.0;
1529  eye.z = 1.0;
1530  top.x = 1.0;
1531  top.y = 1.0;
1532  top.z = 1.0;
1533  break;
1534  case CC_ISO_VIEW_2:
1535  eye.x = 1.0;
1536  eye.y = 1.0;
1537  eye.z = 1.0;
1538  top.x = -1.0;
1539  top.y = -1.0;
1540  top.z = 1.0;
1541  break;
1542  default:
1543  return;
1544  }
1545 
1546  // Normalize the view direction
1547  CCVector3d newViewDir = center - eye;
1548  newViewDir.normalize();
1549 
1550  // Normalize the up vector
1551  top.normalize();
1552 
1553  // Calculate new camera position: keep the focal point, move camera along
1554  // new view direction The new camera position = focal point - (view
1555  // direction * distance) This preserves the zoom level (distance) while
1556  // changing only the orientation
1557  CCVector3d newCameraPos = currentFocalPoint - newViewDir * currentDistance;
1558 
1559  // Set camera with new orientation but preserved distance and focal point
1560  SetCameraPosition(newCameraPos.x, newCameraPos.y, newCameraPos.z,
1561  currentFocalPoint.x, currentFocalPoint.y,
1562  currentFocalPoint.z, top.x, top.y, top.z);
1563 
1566  Deprecate3DLayer();
1567  // Update screen without changing zoom
1568  if (forceRedraw) {
1569  RedrawDisplay();
1570  } else {
1571  UpdateScreen();
1572  }
1573 }
1574 
1575 inline float RoundScale(float equivalentWidth) {
1576  // we compute the scale granularity (to avoid width values with a lot of
1577  // decimals)
1578  int k = static_cast<int>(
1579  std::floor(std::log(equivalentWidth) / std::log(10.0f)));
1580  float granularity = std::pow(10.0f, static_cast<float>(k)) / 2.0f;
1581  // we choose the value closest to equivalentWidth with the right granularity
1582  return std::floor(std::max(equivalentWidth / granularity, 1.0f)) *
1583  granularity;
1584 }
1585 
1587  // DGM: in fact it can be useful to compute it even in ortho mode :)
1588  // if (!m_viewportParams.perspectiveView)
1589  // return m_viewportParams.zoom;
1590 
1591  // we compute the zoom equivalent to the corresponding camera position
1592  // (inverse of above calculus)
1593  float currentFov_deg = GetFov();
1594  if (currentFov_deg < FLT_EPSILON) return 1.0f;
1595 
1596  // Camera center to pivot vector
1597  double zoomEquivalentDist =
1598  (s_tools.instance->m_viewportParams.getCameraCenter() -
1599  s_tools.instance->m_viewportParams.getPivotPoint())
1600  .norm();
1601  if (cloudViewer::LessThanEpsilon(zoomEquivalentDist)) return 1.0f;
1602 
1603  float screenSize = std::min(s_tools.instance->m_glViewport.width(),
1604  s_tools.instance->m_glViewport.height()) *
1605  s_tools.instance->m_viewportParams
1606  .pixelSize; // see how pixelSize is computed!
1607  return screenSize /
1608  static_cast<float>(
1609  zoomEquivalentDist *
1610  std::tan(cloudViewer::DegreesToRadians(currentFov_deg)));
1611 }
1612 
1614  if (!s_tools.instance->m_validModelviewMatrix) UpdateModelViewMatrix();
1615 
1616  return s_tools.instance->m_viewMatd;
1617 }
1618 
1620  if (!s_tools.instance->m_validProjectionMatrix) UpdateProjectionMatrix();
1621 
1622  return s_tools.instance->m_projMatd;
1623 }
1624 
1626  bool withGLfeatures,
1627  ProjectionMetrics* metrics /*=nullptr*/,
1628  double* eyeOffset /*=nullptr*/) {
1629  double bbHalfDiag = 1.0;
1630  CCVector3d bbCenter(0, 0, 0);
1631 
1632  // compute center of visible objects constellation
1633  if (s_tools.instance->m_globalDBRoot || s_tools.instance->m_winDBRoot) {
1634  // get whole bounding-box
1635  ccBBox box;
1636  GetVisibleObjectsBB(box);
1637  if (box.isValid()) {
1638  // get bbox center
1639  bbCenter = CCVector3d::fromArray(box.getCenter().u);
1640  // get half bbox diagonal length
1641  bbHalfDiag = box.getDiagNormd() / 2;
1642  }
1643  }
1644 
1645  CCVector3d cameraCenterToBBCenter =
1646  s_tools.instance->m_viewportParams.getCameraCenter() - bbCenter;
1647  double cameraToBBCenterDist = cameraCenterToBBCenter.normd();
1648 
1649  if (metrics) {
1650  metrics->bbHalfDiag = bbHalfDiag;
1651  metrics->cameraToBBCenterDist = cameraToBBCenterDist;
1652  }
1653 
1654  // virtual pivot point (i.e. to handle viewer-based mode smoothly)
1655  CCVector3d rotationCenter =
1656  s_tools.instance->m_viewportParams.getRotationCenter();
1657 
1658  // compute the maximum distance between the pivot point and the farthest
1659  // displayed object
1660  double rotationCenterToFarthestObjectDist = 0.0;
1661  {
1662  // maximum distance between the pivot point and the farthest corner of
1663  // the displayed objects bounding-box
1664  rotationCenterToFarthestObjectDist =
1665  (bbCenter - rotationCenter).norm() + bbHalfDiag;
1666 
1667  //(if enabled) the pivot symbol should always be visible in
1668  // object-centere view mode
1669  if (s_tools.instance->m_pivotSymbolShown &&
1670  s_tools.instance->m_pivotVisibility != PIVOT_HIDE &&
1671  withGLfeatures &&
1672  s_tools.instance->m_viewportParams.objectCenteredView) {
1673  double pivotActualRadius =
1675  std::min(s_tools.instance->m_glViewport.width(),
1676  s_tools.instance->m_glViewport.height()) /
1677  2;
1678  double pivotSymbolScale =
1679  pivotActualRadius * ComputeActualPixelSize();
1680  rotationCenterToFarthestObjectDist = std::max(
1681  rotationCenterToFarthestObjectDist, pivotSymbolScale);
1682  }
1683 
1684  if (withGLfeatures && s_tools.instance->m_customLightEnabled) {
1685  // distance from custom light to pivot point
1686  double distToCustomLight =
1687  (rotationCenter -
1688  CCVector3d::fromArray(s_tools.instance->m_customLightPos))
1689  .norm();
1690  rotationCenterToFarthestObjectDist = std::max(
1691  rotationCenterToFarthestObjectDist, distToCustomLight);
1692  }
1693 
1694  rotationCenterToFarthestObjectDist *= 1.01; // for round-off issues
1695  }
1696 
1697  double cameraCenterToRotationCentertDist = 0;
1698  if (s_tools.instance->m_viewportParams.objectCenteredView) {
1699  cameraCenterToRotationCentertDist =
1700  s_tools.instance->m_viewportParams.getFocalDistance();
1701  }
1702 
1703  // we deduce zFar
1704  double zNear = cameraCenterToRotationCentertDist -
1705  rotationCenterToFarthestObjectDist;
1706  double zFar = cameraCenterToRotationCentertDist +
1707  rotationCenterToFarthestObjectDist;
1708 
1709  // compute the aspect ratio
1710  double ar = static_cast<double>(s_tools.instance->m_glViewport.height()) /
1711  s_tools.instance->m_glViewport.width();
1712 
1713  ccGLMatrixd projMatrix;
1714  if (s_tools.instance->m_viewportParams.perspectiveView) {
1715  // DGM: the 'zNearCoef' must not be too small, otherwise the loss in
1716  // accuracy for the detph buffer is too high and the display is
1717  // jeopardized, especially for entities with large coordinates) zNear =
1718  // zFar * m_viewportParams.zNearCoef;
1719  zNear = bbHalfDiag * s_tools.instance->m_viewportParams
1720  .zNearCoef; // we want a stable value!
1721  // zNear = std::max(bbHalfDiag * m_viewportParams.zNearCoef, zNear);
1722  // //we want a stable value!
1723  zFar = std::max(zNear + ZERO_TOLERANCE_D, zFar);
1724 
1725  double xMax = zNear * s_tools.instance->m_viewportParams
1726  .computeDistanceToHalfWidthRatio();
1727  double yMax = xMax * ar;
1728 
1729  // DGM: we now take 'frustumAsymmetry' into account (for stereo
1730  // rendering)
1731  double frustumAsymmetry = 0.0;
1732  projMatrix = ecvGenericDisplayTools::Frustum(-xMax - frustumAsymmetry,
1733  xMax - frustumAsymmetry,
1734  -yMax, yMax, zNear, zFar);
1735  } else {
1736  // zNear = std::max(zNear, 0.0);
1737  zFar = std::max(zNear + ZERO_TOLERANCE_D, zFar);
1738 
1739  // CVLog::Print(QString("cameraCenterToPivotDist = %0 / zNear = %1 /
1740  // zFar = %2").arg(cameraCenterToPivotDist).arg(zNear).arg(zFar));
1741 
1742  double xMax = std::abs(cameraCenterToRotationCentertDist) *
1743  s_tools.instance->m_viewportParams
1744  .computeDistanceToHalfWidthRatio();
1745  double yMax = xMax * ar;
1746 
1747  projMatrix = ecvGenericDisplayTools::Ortho(-xMax, xMax, -yMax, yMax,
1748  zNear, zFar);
1749  }
1750  return projMatrix;
1751 }
1752 
1754  ProjectionMetrics metrics;
1755 
1756  s_tools.instance->m_projMatd =
1757  ComputeProjectionMatrix(true, &metrics,
1758  nullptr); // no stereo vision by default!
1759 
1760  s_tools.instance->m_viewportParams.zNear = metrics.zNear;
1761  s_tools.instance->m_viewportParams.zFar = metrics.zFar;
1762  s_tools.instance->m_cameraToBBCenterDist = metrics.cameraToBBCenterDist;
1763  s_tools.instance->m_bbHalfDiag = metrics.bbHalfDiag;
1764 
1765  s_tools.instance->m_validProjectionMatrix = true;
1766 }
1767 
1769  // the camera center is always defined in perspective mode
1770  if (s_tools.instance->m_viewportParams.perspectiveView) {
1771  return s_tools.instance->m_viewportParams.getCameraCenter();
1772  }
1773 
1774  // in orthographic mode, we put the camera at the center of the
1775  // visible objects (along the viewing direction)
1776  ccBBox box;
1777  GetVisibleObjectsBB(box);
1778 
1779  return CCVector3d(s_tools.instance->m_viewportParams.getCameraCenter().x,
1780  s_tools.instance->m_viewportParams.getCameraCenter().y,
1781  box.isValid() ? box.getCenter().z : 0.0);
1782 }
1783 
1785  ccGLMatrixd viewMatd =
1786  s_tools.instance->m_viewportParams.computeViewMatrix();
1787 
1788  ccGLMatrixd scaleMatd =
1789  s_tools.instance->m_viewportParams.computeScaleMatrix(
1790  s_tools.instance->m_glViewport);
1791 
1792  return scaleMatd * viewMatd;
1793 }
1794 
1796  // we save visualization matrix
1797  s_tools.instance->m_viewMatd = ComputeModelViewMatrix();
1798 
1799  s_tools.instance->m_validModelviewMatrix = true;
1800 }
1801 
1803  s_tools.instance->m_viewportParams.viewMat = mat;
1804 
1806 
1807  // we emit the 'baseViewMatChanged' signal
1808  emit s_tools.instance->baseViewMatChanged(
1809  s_tools.instance->m_viewportParams.viewMat);
1810  emit s_tools.instance->cameraParamChanged();
1811 }
1812 
1813 void ecvDisplayTools::SetPerspectiveState(bool state, bool objectCenteredView) {
1814  // previous state
1815  bool perspectiveWasEnabled =
1816  s_tools.instance->m_viewportParams.perspectiveView;
1817  bool viewWasObjectCentered =
1818  s_tools.instance->m_viewportParams.objectCenteredView;
1819 
1820  // new state
1821  s_tools.instance->m_viewportParams.perspectiveView = state;
1822  s_tools.instance->m_viewportParams.objectCenteredView = objectCenteredView;
1823 
1824  // Camera center to pivot vector
1825  CCVector3d PC = s_tools.instance->m_viewportParams.getCameraCenter() -
1826  s_tools.instance->m_viewportParams.getPivotPoint();
1827 
1828  if (s_tools.instance->m_viewportParams.perspectiveView) {
1829  if (!perspectiveWasEnabled) // from ortho. mode to perspective view
1830  {
1831  // we compute the camera position that gives 'quite' the same view
1832  // as the ortho one (i.e. we replace the zoom by setting the camera
1833  // at the right distance from the pivot point)
1834  double currentFov_deg = static_cast<double>(GetFov());
1835  assert(cloudViewer::GreaterThanEpsilon(currentFov_deg));
1836  // see how pixelSize is computed!
1837  double screenSize =
1838  std::min(s_tools.instance->m_glViewport.width(),
1839  s_tools.instance->m_glViewport.height()) *
1840  s_tools.instance->m_viewportParams.pixelSize;
1841  if (screenSize > 0.0) {
1842  PC.z = screenSize / (s_tools.instance->m_viewportParams.zoom *
1844  currentFov_deg)));
1845  }
1846  }
1847 
1848  // display message
1849  DisplayNewMessage(objectCenteredView ? "Centered perspective ON"
1850  : "Viewer-based perspective ON",
1851  LOWER_LEFT_MESSAGE, false, 2,
1853  } else {
1854  // object-centered mode is forced for otho. view
1855  s_tools.instance->m_viewportParams.objectCenteredView = true;
1856 
1857  if (perspectiveWasEnabled) // from perspective view to ortho. view
1858  {
1859  // we compute the zoom equivalent to the corresponding camera
1860  // position (inverse of above calculus)
1861  float newZoom = ComputePerspectiveZoom();
1862  SetZoom(newZoom);
1863  }
1864 
1865  DisplayNewMessage("Perspective OFF", LOWER_LEFT_MESSAGE, false, 2,
1867  }
1868 
1869  // if we change form object-based to viewer-based visualization, we must
1870  //'rotate' around the object (or the opposite ;)
1871  if (viewWasObjectCentered &&
1872  !s_tools.instance->m_viewportParams.objectCenteredView) {
1873  s_tools.instance->m_viewportParams.viewMat.transposed().apply(
1874  PC); // inverse rotation
1875  } else if (!viewWasObjectCentered &&
1876  s_tools.instance->m_viewportParams.objectCenteredView) {
1877  s_tools.instance->m_viewportParams.viewMat.apply(PC);
1878  }
1879 
1880  SetCameraPos(s_tools.instance->m_viewportParams.getPivotPoint() + PC);
1881 
1882  emit s_tools.instance->perspectiveStateChanged();
1883  emit s_tools.instance->cameraParamChanged();
1884 
1885  // auto-save last perspective settings
1886  {
1887  QSettings settings;
1888  settings.beginGroup(c_ps_groupName);
1889  // write parameters
1890  settings.setValue(c_ps_perspectiveView,
1891  s_tools.instance->m_viewportParams.perspectiveView);
1892  settings.setValue(
1894  s_tools.instance->m_viewportParams.objectCenteredView);
1895  settings.endGroup();
1896  }
1897 
1898  s_tools.instance->m_bubbleViewModeEnabled = false;
1899 
1902  Deprecate3DLayer();
1903 }
1904 
1906  bool perspectiveWasEnabled =
1907  s_tools.instance->m_viewportParams.perspectiveView;
1908  bool viewWasObjectCentered =
1909  s_tools.instance->m_viewportParams.objectCenteredView;
1910  return perspectiveWasEnabled && viewWasObjectCentered;
1911 }
1912 
1914  bool perspectiveWasEnabled =
1915  s_tools.instance->m_viewportParams.perspectiveView;
1916  bool viewWasObjectCentered =
1917  s_tools.instance->m_viewportParams.objectCenteredView;
1918  return perspectiveWasEnabled && !viewWasObjectCentered;
1919 }
1920 
1922  bool redraw) {
1923  if (s_tools.instance->m_bubbleViewModeEnabled) {
1925  "[updateConstellationCenterAndZoom] Not when bubble-view is "
1926  "enabled!");
1927  return;
1928  }
1929 
1930  SetZoom(1.0f);
1931 
1932  ccBBox zoomedBox;
1933 
1934  // the user has provided a valid bounding box
1935  if (aBox) {
1936  zoomedBox = (*aBox);
1937  } else // otherwise we'll take the default one (if possible)
1938  {
1939  GetVisibleObjectsBB(zoomedBox);
1940  }
1941 
1942  if (!zoomedBox.isValid()) {
1943  return;
1944  }
1945 
1946  if (redraw) {
1949  Deprecate3DLayer();
1950  RedrawDisplay();
1951  }
1952 
1953  // we get the bounding-box diagonal length
1954  double bbDiag = static_cast<double>(zoomedBox.getDiagNorm());
1955 
1956  if (cloudViewer::LessThanEpsilon(bbDiag)) {
1957  CVLog::Warning("[ecvDisplayTools] Entity/DB has a null bounding-box!");
1958  return;
1959  }
1960 
1961  // Add margin to bounding box to ensure objects are fully visible
1962  // and not clipped at the edges (default 10% margin)
1963  const double margin = 1.1; // 10% margin on all sides
1964  if (margin > 1.0) {
1965  CCVector3d centerVec = CCVector3d::fromArray(zoomedBox.getCenter().u);
1966  Eigen::Vector3d center(centerVec.x, centerVec.y, centerVec.z);
1967  zoomedBox.Scale(margin, center);
1968  }
1969 
1970  ResetCamera(&zoomedBox);
1971  UpdateScreen();
1972 
1973  // we compute the pixel size (in world coordinates)
1974  {
1975  int minScreenSize = std::min(s_tools.instance->m_glViewport.width(),
1976  s_tools.instance->m_glViewport.height());
1977  SetPixelSize(minScreenSize > 0
1978  ? static_cast<float>(bbDiag / minScreenSize)
1979  : 1.0f);
1980  }
1981 
1982  // we set the pivot point on the box center
1983  CCVector3d P = CCVector3d::fromArray(zoomedBox.getCenter().u);
1984  SetPivotPoint(P);
1985 
1986  // CRITICAL: Update 2D labels after zoom operation to ensure they align with
1987  // their 3D anchor points. This fixes the issue where labels become detached
1988  // after zoom operations (zoom on selected, zoom to box, zoom to global).
1989  s_tools.instance->Update2DLabel(true);
1990 }
1991 
1992 void ecvDisplayTools::SetRedrawRecursive(bool redraw /* = false*/) {
1994  GetOwnDB()->setRedrawFlagRecursive(redraw);
1995 }
1996 
2000 }
2001 
2003  bool redraw /* = false*/) {
2004  assert(obj);
2005  obj->setRedrawFlagRecursive(redraw);
2006 }
2007 
2009  // compute center of visible objects constellation
2010  if (s_tools.instance->m_globalDBRoot) {
2011  // get whole bounding-box
2012  box = s_tools.instance->m_globalDBRoot->getDisplayBB_recursive(false);
2013  }
2014 
2015  // incorporate window own db
2016  if (s_tools.instance->m_winDBRoot) {
2017  ccBBox ownBox =
2018  s_tools.instance->m_winDBRoot->getDisplayBB_recursive(false);
2019  if (ownBox.isValid()) {
2020  box += ownBox;
2021  }
2022  }
2023 }
2024 
2026  ENTITY_TYPE entityType = ENTITY_TYPE::ECV_NONE;
2027  switch (type) {
2029  entityType = ENTITY_TYPE::ECV_HIERARCHY_OBJECT;
2030  break;
2031  case CV_TYPES::POINT_CLOUD:
2032  entityType = ENTITY_TYPE::ECV_POINT_CLOUD;
2033  break;
2034  case CV_TYPES::POLY_LINE:
2035  case CV_TYPES::LINESET:
2036  entityType = ENTITY_TYPE::ECV_SHAPE;
2037  break;
2038  case CV_TYPES::LABEL_2D:
2039  entityType = ENTITY_TYPE::ECV_2DLABLE;
2040  break;
2042  entityType = ENTITY_TYPE::ECV_2DLABLE_VIEWPORT;
2043  break;
2045  entityType = ENTITY_TYPE::ECV_OCTREE;
2046  break;
2048  entityType = ENTITY_TYPE::ECV_KDTREE;
2049  break;
2050  case CV_TYPES::FACET:
2051  case CV_TYPES::PRIMITIVE:
2052  case CV_TYPES::MESH:
2053  case CV_TYPES::SUB_MESH:
2054  case CV_TYPES::SPHERE:
2055  case CV_TYPES::CONE:
2056  case CV_TYPES::PLANE:
2057  case CV_TYPES::CYLINDER:
2058  case CV_TYPES::TORUS:
2059  case CV_TYPES::EXTRU:
2060  case CV_TYPES::DISH:
2061  case CV_TYPES::DISC:
2062  case CV_TYPES::BOX:
2064  case CV_TYPES::QUADRIC:
2065  entityType = ENTITY_TYPE::ECV_MESH;
2066  break;
2067  case CV_TYPES::IMAGE:
2068  entityType = ENTITY_TYPE::ECV_IMAGE;
2069  break;
2070  case CV_TYPES::SENSOR:
2071  case CV_TYPES::GBL_SENSOR:
2073  entityType = ENTITY_TYPE::ECV_SENSOR;
2074  break;
2075  default:
2076  break;
2077  }
2078  return entityType;
2079 }
2080 
2082  s_tools.instance->m_displayOverlayEntities = state;
2083  if (!state) {
2084  ClearBubbleView();
2085  }
2086 }
2087 
2089  s_tools.instance->m_globalDBRoot = root;
2090  ZoomGlobal();
2091 }
2092 
2093 void ecvDisplayTools::AddToOwnDB(ccHObject* obj, bool noDependency /*=true*/) {
2094  if (!obj) {
2095  assert(false);
2096  return;
2097  }
2098 
2099  if (s_tools.instance->m_winDBRoot) {
2100  s_tools.instance->m_winDBRoot->addChild(
2101  obj, noDependency ? ccHObject::DP_NONE
2103  } else {
2104  CVLog::Error("[ecvDisplayTools::addToOwnDB] Window has no DB!");
2105  }
2106 }
2107 
2109  if (s_tools.instance->m_winDBRoot)
2110  s_tools.instance->m_winDBRoot->removeChild(obj);
2111 }
2112 
2113 void ecvDisplayTools::SetRemoveViewIDs(std::vector<removeInfo>& removeinfos) {
2114  if (removeinfos.size() > 0) {
2115  s_tools.instance->m_removeInfos = removeinfos;
2116  s_tools.instance->m_removeFlag = true;
2117  } else {
2118  s_tools.instance->m_removeFlag = false;
2119  }
2120 }
2121 
2122 void ecvDisplayTools::ZoomCamera(double zoomFactor, int viewport) {
2123  TheInstance()->zoomCamera(zoomFactor, viewport);
2125  TheInstance()->UpdateZoom(static_cast<float>(zoomFactor));
2126  }
2128 }
2129 
2130 void ecvDisplayTools::SetInteractionMode(INTERACTION_FLAGS flags) {
2131  s_tools.instance->m_interactionFlags = flags;
2132 
2133  // we need to explicitely enable 'mouse tracking' to track the mouse when no
2134  // button is clicked
2135 #ifdef CV_GL_WINDOW_USE_QWINDOW
2136  if (m_parentWidget) {
2137  m_parentWidget->setMouseTracking(
2139  }
2140 #else
2141  GetCurrentScreen()->setMouseTracking(
2143 #endif
2144 
2145  if ((flags & INTERACT_CLICKABLE_ITEMS) == 0) {
2146  // auto-hide the embedded icons if they are disabled
2147  s_tools.instance->m_clickableItemsVisible = false;
2148  }
2149 }
2150 
2151 ecvDisplayTools::INTERACTION_FLAGS ecvDisplayTools::GetInteractionMode() {
2152  return s_tools.instance->m_interactionFlags;
2153 }
2154 
2156  // view direction is (the opposite of) the 3rd line of the current view
2157  // matrix
2158  const double* M = s_tools.instance->m_viewportParams.viewMat.data();
2159  CCVector3d axis(-M[2], -M[6], -M[10]);
2160  axis.normalize();
2161 
2162  return axis;
2163 }
2164 
2166  // otherwise up direction is the 2nd line of the current view matrix
2167  const double* M = s_tools.instance->m_viewportParams.viewMat.data();
2168  CCVector3d axis(M[1], M[5], M[9]);
2169  axis.normalize();
2170 
2171  return axis;
2172 }
2173 
2175  return (s_tools.instance->m_bubbleViewModeEnabled
2176  ? s_tools.instance->m_bubbleViewFov_deg
2177  : s_tools.instance->m_viewportParams.fov_deg);
2178 }
2179 
2181  const ccGLMatrixd& cameraMatrix,
2182  float fov_deg /*=0.0f*/,
2183  float ar /*=1.0f*/,
2184  bool viewerBasedPerspective /*=true*/,
2185  bool bubbleViewMode /*=false*/) {
2186  // perspective (viewer-based by default)
2187  if (bubbleViewMode) {
2188  SetBubbleViewMode(true);
2189  } else {
2190  SetPerspectiveState(true, !viewerBasedPerspective);
2191  }
2192 
2193  // field of view (= OpenGL 'fovy' but in degrees)
2194  if (fov_deg > 0.0f) {
2195  if (s_tools.instance->m_viewportParams.perspectiveView) {
2196  SetFov(fov_deg);
2197  } else {
2199  static_cast<double>(cloudViewer::DegreesToRadians(fov_deg)),
2200  0);
2201  }
2202  }
2203 
2204  // aspect ratio
2205  SetAspectRatio(ar);
2206 
2207  // set the camera matrix 'translation' as OpenGL camera center
2208  CCVector3d T = cameraMatrix.getTranslationAsVec3D();
2209  CCVector3d UP = cameraMatrix.getColumnAsVec3D(1);
2210  cameraMatrix.applyRotation(UP.data());
2211  SetCameraPos(T);
2212  SetCameraPosition(T.data(), UP.data());
2213  if (viewerBasedPerspective && s_tools.instance->m_autoPickPivotAtCenter) {
2214  SetPivotPoint(T);
2215  }
2216 
2217  // apply orientation matrix
2218  ccGLMatrixd trans = cameraMatrix;
2219  trans.clearTranslation();
2220  trans.invert();
2221  SetBaseViewMat(trans);
2222 
2224  UpdateScreen();
2225 }
2226 
2228  if (ar < 0.0f) {
2229  CVLog::Warning("[ecvDisplayTools::setAspectRatio] Invalid AR value!");
2230  return;
2231  }
2232 
2233  if (s_tools.instance->m_viewportParams.cameraAspectRatio != ar) {
2234  // update param
2235  s_tools.instance->m_viewportParams.cameraAspectRatio = ar;
2236 
2237  // and camera state
2240  Deprecate3DLayer();
2241  }
2242 }
2243 
2244 void ecvDisplayTools::SetFov(float fov_deg) {
2245  if (cloudViewer::LessThanEpsilon(fov_deg) || fov_deg > 180.0f) {
2246  CVLog::Warning("[ecvDisplayTools::setFov] Invalid FOV value!");
2247  return;
2248  }
2249 
2250  // derivation if we are in bubble-view mode
2251  if (s_tools.instance->m_bubbleViewModeEnabled) {
2252  SetBubbleViewFov(fov_deg);
2253  } else if (s_tools.instance->m_viewportParams.fov_deg != fov_deg) {
2254  // update param
2255  s_tools.instance->m_viewportParams.fov_deg = fov_deg;
2256  // and camera state (if perspective view is 'on')
2257  {
2258  SetCameraFovy(fov_deg);
2261  Deprecate3DLayer();
2262 
2264  QString("F.O.V. = %1 deg.").arg(fov_deg, 0, 'f', 1),
2265  LOWER_LEFT_MESSAGE, // DGM HACK: we cheat and use the same
2266  // 'slot' as the window size
2267  false, 2, SCREEN_SIZE_MESSAGE);
2268  }
2269 
2270  emit s_tools.instance->fovChanged(
2271  s_tools.instance->m_viewportParams.fov_deg);
2272  emit s_tools.instance->cameraParamChanged();
2273  }
2274 }
2275 
2276 void ecvDisplayTools::DisplayNewMessage(const QString& message,
2277  MessagePosition pos,
2278  bool append /*=false*/,
2279  int displayMaxDelay_sec /*=2*/,
2280  MessageType type /*=CUSTOM_MESSAGE*/) {
2281  if (message.isEmpty()) {
2282  if (!append) {
2283  std::list<MessageToDisplay>::iterator it =
2284  s_tools.instance->m_messagesToDisplay.begin();
2285  while (it != s_tools.instance->m_messagesToDisplay.end()) {
2286  // same position? we remove the message
2287  if (it->position == pos) {
2289  it->message));
2290  it = s_tools.instance->m_messagesToDisplay.erase(it);
2291  } else
2292  ++it;
2293  }
2294  } else {
2296  "[ecvDisplayTools::DisplayNewMessage] Appending an empty "
2297  "message has no effect!");
2298  }
2299  return;
2300  }
2301 
2302  // shall we replace the equivalent message(if any)?
2303  if (!append) {
2304  // only if type is not 'custom'
2305  if (type != CUSTOM_MESSAGE) {
2306  for (std::list<MessageToDisplay>::iterator it =
2307  s_tools.instance->m_messagesToDisplay.begin();
2308  it != s_tools.instance->m_messagesToDisplay.end();) {
2309  // same type? we remove it
2310  if (it->type == type) {
2312  it->message));
2313  it = s_tools.instance->m_messagesToDisplay.erase(it);
2314  } else
2315  ++it;
2316  }
2317  }
2318  } else {
2319  if (pos == SCREEN_CENTER_MESSAGE) {
2321  "[ecvDisplayTools::DisplayNewMessage] Append is not "
2322  "supported for center screen messages!");
2323  }
2324  }
2325 
2326  MessageToDisplay mess;
2327  mess.message = message;
2328  mess.messageValidity_sec =
2329  s_tools.instance->m_timer.elapsed() / 1000 + displayMaxDelay_sec;
2330  mess.position = pos;
2331  mess.type = type;
2332  s_tools.instance->m_messagesToDisplay.push_back(mess);
2333  // CVLog::Print(QString("[DisplayNewMessage] New message valid until %1
2334  // s.").arg(mess.messageValidity_sec));
2335 }
2336 
2338  bool autoUpdateCameraPos /*=false*/,
2339  bool verbose /*=false*/) {
2340  if (autoUpdateCameraPos &&
2341  (!s_tools.instance->m_viewportParams.perspectiveView ||
2342  s_tools.instance->m_viewportParams.objectCenteredView)) {
2343  // compute the equivalent camera center
2344  CCVector3d dP = s_tools.instance->m_viewportParams.getPivotPoint() - P;
2345  CCVector3d MdP = dP;
2346  s_tools.instance->m_viewportParams.viewMat.applyRotation(MdP);
2347  CCVector3d newCameraPos =
2348  s_tools.instance->m_viewportParams.getCameraCenter() + MdP - dP;
2349  SetCameraPos(newCameraPos);
2350  }
2351 
2352  s_tools.instance->m_viewportParams.setPivotPoint(P, true);
2353  SetAutoUpateCameraPos(autoUpdateCameraPos);
2355 
2356  emit s_tools.instance->pivotPointChanged(
2357  s_tools.instance->m_viewportParams.getPivotPoint());
2358  emit s_tools.instance->cameraParamChanged();
2359 
2360  if (verbose) {
2361  const unsigned& precision =
2364  false); // clear previous message
2365  DisplayNewMessage(QString("Point (%1 ; %2 ; %3) set as rotation center")
2366  .arg(P.x, 0, 'f', precision)
2367  .arg(P.y, 0, 'f', precision)
2368  .arg(P.z, 0, 'f', precision),
2369  LOWER_LEFT_MESSAGE, true);
2370  RedrawDisplay(true, false);
2371  }
2372 
2373  // s_tools.instance->m_autoPivotCandidate = CCVector3d(0, 0, 0);
2374  s_tools.instance->m_autoPivotCandidate = P;
2377 }
2378 
2380  if (s_tools.instance->m_autoPickPivotAtCenter != state) {
2381  s_tools.instance->m_autoPickPivotAtCenter = state;
2382 
2383  if (state) {
2384  // force 3D redraw to update the coordinates of the 'auto' pivot
2385  // center
2386  s_tools.instance->m_autoPivotCandidate = CCVector3d(0, 0, 0);
2387  // RedrawDisplay(false);
2388  }
2389  }
2390 }
2391 
2392 void ecvDisplayTools::LockRotationAxis(bool state, const CCVector3d& axis) {
2393  s_tools.instance->m_rotationAxisLocked = state;
2394  s_tools.instance->m_lockedRotationAxis = axis;
2395  s_tools.instance->m_lockedRotationAxis.normalize();
2396 }
2397 
2399  // display size
2400  CONTEXT.glW = s_tools.instance->m_glViewport.width();
2401  CONTEXT.glH = s_tools.instance->m_glViewport.height();
2402  CONTEXT.devicePixelRatio = static_cast<float>(GetDevicePixelRatio());
2403  CONTEXT.drawingFlags = 0;
2404 
2405  const ecvGui::ParamStruct& guiParams = GetDisplayParameters();
2406 
2407  // decimation options
2408  CONTEXT.decimateCloudOnMove = guiParams.decimateCloudOnMove;
2409  CONTEXT.minLODPointCount = guiParams.minLoDCloudSize;
2410  CONTEXT.minLODTriangleCount = guiParams.minLoDMeshSize;
2411  CONTEXT.higherLODLevelsAvailable = false;
2412  CONTEXT.moreLODPointsAvailable = false;
2413  CONTEXT.currentLODLevel = 0;
2414 
2415  // scalar field color-bar
2416  CONTEXT.sfColorScaleToDisplay = nullptr;
2417 
2418  // point picking
2419  CONTEXT.labelMarkerSize = static_cast<float>(guiParams.labelMarkerSize *
2421  CONTEXT.labelMarkerTextShift_pix = 5; // 5 pixels shift
2422 
2423  // text display
2424  CONTEXT.dispNumberPrecision = guiParams.displayedNumPrecision;
2425  // label opacity
2426  CONTEXT.labelOpacity = guiParams.labelOpacity;
2427 
2428  // default materials
2429  CONTEXT.defaultMat->setDiffuseFront(guiParams.meshFrontDiff);
2430  CONTEXT.defaultMat->setDiffuseBack(guiParams.meshBackDiff);
2431  CONTEXT.defaultMat->setAmbient(ecvColor::bright);
2432  CONTEXT.defaultMat->setSpecular(guiParams.meshSpecular);
2433  CONTEXT.defaultMat->setEmission(ecvColor::night);
2434  CONTEXT.defaultMat->setShininessFront(30);
2435  CONTEXT.defaultMat->setShininessBack(50);
2436 
2437  // default colors
2438  CONTEXT.pointsDefaultCol = guiParams.pointsDefaultCol;
2439  CONTEXT.textDefaultCol = guiParams.textDefaultCol;
2440  CONTEXT.labelDefaultBkgCol = guiParams.labelBackgroundCol;
2441  CONTEXT.labelDefaultMarkerCol = guiParams.labelMarkerCol;
2442  CONTEXT.bbDefaultCol = guiParams.bbDefaultCol;
2443 
2444  // display acceleration
2445  CONTEXT.useVBOs = guiParams.useVBOs;
2446 
2447  // other options
2448  CONTEXT.drawRoundedPoints = guiParams.drawRoundedPoints;
2449 }
2450 
2452  float zoomFactor /*=1.0*/,
2453  bool dontScaleFeatures /*=false*/,
2454  bool renderOverlayItems /*=false*/) {
2455  if (filename.isEmpty() || zoomFactor < 1.0e-2f) {
2456  return false;
2457  }
2458 
2459  QImage outputImage = RenderToImage(static_cast<int>(zoomFactor),
2460  renderOverlayItems, false, 0);
2461 
2462  if (outputImage.isNull()) {
2463  // an error occurred (message should have already been issued!)
2464  return false;
2465  }
2466 
2467  if (GetDisplayParameters().drawRoundedPoints) {
2468  // convert the image to plain RGB to avoid issues with points
2469  // transparency when saving to PNG
2470  outputImage = outputImage.convertToFormat(QImage::Format_RGB32);
2471  }
2472 
2473  bool success =
2474  outputImage.convertToFormat(QImage::Format_RGB32).save(filename);
2475  if (success) {
2476  CVLog::Print(QString("[Snapshot] File '%1' saved! (%2 x %3 pixels)")
2477  .arg(filename)
2478  .arg(outputImage.width())
2479  .arg(outputImage.height()));
2480  } else {
2481  CVLog::Print(
2482  QString("[Snapshot] Failed to save file '%1'!").arg(filename));
2483  }
2484 
2485  return success;
2486 }
2487 
2489  if ((s_tools.instance->m_viewportParams.getCameraCenter() - P).norm2d() !=
2490  0.0) {
2491  s_tools.instance->m_viewportParams.setCameraCenter(P, true);
2492  SetCameraPosition(P);
2493  emit s_tools.instance->cameraPosChanged(
2494  s_tools.instance->m_viewportParams.getCameraCenter());
2495  emit s_tools.instance->cameraParamChanged();
2498  Deprecate3DLayer();
2499  }
2500 }
2501 
2503  if (s_tools.instance->m_overridenDisplayParametersEnabled) {
2504  s_tools.instance->m_overridenDisplayParameters.initFontSizesIfNeeded();
2505  return s_tools.instance->m_overridenDisplayParameters;
2506  } else {
2507  const ecvGui::ParamStruct& params = ecvGui::Parameters();
2509  return params;
2510  }
2511 }
2512 
2514  // get/compute the modelview matrix
2515  { GetViewMatrix(params.modelViewMat.data()); }
2516 
2517  // get/compute the projection matrix
2518  { GetProjectionMatrix(params.projectionMat.data()); }
2519 
2520  ccGLMatrixd rotationMat;
2521  rotationMat.setRotation(
2522  ccGLMatrixd::ToEigenMatrix3(params.modelViewMat).data());
2523  s_tools.instance->m_viewportParams.viewMat = rotationMat;
2524  double nearFar[2];
2525  GetCameraClip(nearFar);
2526 
2527  CCVector3d pivot;
2528  GetCenterOfRotation(pivot);
2529  s_tools.instance->m_viewportParams.setPivotPoint(pivot);
2530 
2531  s_tools.instance->m_viewportParams.zNear = nearFar[0];
2532  s_tools.instance->m_viewportParams.zFar = nearFar[1];
2533  s_tools.instance->m_viewportParams.fov_deg =
2534  static_cast<float>(GetCameraFovy());
2535  params.fov_deg = s_tools.instance->m_viewportParams.fov_deg;
2536 
2537  params.viewport[0] = 0;
2538  params.viewport[1] = 0;
2539  params.viewport[2] = Width() * GetDevicePixelRatio();
2540  params.viewport[3] = Height() * GetDevicePixelRatio();
2541  SetGLViewport(QRect(0, 0, Width(), Height()));
2542 
2543  params.perspective = s_tools.instance->m_viewportParams.perspectiveView;
2544  params.pixelSize = s_tools.instance->m_viewportParams.pixelSize;
2545 }
2546 
2548  s_tools.instance->m_overridenDisplayParametersEnabled = true;
2549  s_tools.instance->m_overridenDisplayParameters = params;
2550  s_tools.instance->m_overridenDisplayParameters.initFontSizesIfNeeded();
2551  ecvGui::Set(params);
2552 }
2553 
2555  // set camera near and far
2556  double nearFar[2];
2557  GetCameraClip(nearFar);
2558  s_tools.instance->m_viewportParams.zNear = nearFar[0];
2559  s_tools.instance->m_viewportParams.zFar = nearFar[1];
2560 
2561  ccGLMatrixd viewMat;
2562  GetViewMatrix(viewMat.data());
2563  ccGLMatrixd rotationMat;
2564  rotationMat.setRotation(ccGLMatrixd::ToEigenMatrix3(viewMat).data());
2565  s_tools.instance->m_viewportParams.viewMat = rotationMat;
2566 
2567  CCVector3d pivot;
2568  GetCenterOfRotation(pivot);
2569  s_tools.instance->m_viewportParams.setPivotPoint(pivot);
2570 
2571  // set camera fov
2572  if (s_tools.instance->m_viewportParams.perspectiveView) {
2573  s_tools.instance->m_viewportParams.zoom = ComputePerspectiveZoom();
2574  s_tools.instance->m_viewportParams.fov_deg =
2575  static_cast<float>(GetCameraFovy());
2576  } else {
2577  s_tools.instance->m_viewportParams.fov_deg = static_cast<float>(
2579  }
2580 
2581  // set camera pos
2582  double pos[3];
2583  GetCameraPos(pos);
2584  s_tools.instance->m_viewportParams.setCameraCenter(
2585  CCVector3d::fromArray(pos), true);
2586 
2587  // set camera focal
2588  double focal[3];
2589  GetCameraFocal(focal);
2590  s_tools.instance->m_viewportParams.focal = CCVector3d::fromArray(focal);
2591 
2592  // set camera up
2593  double up[3];
2594  GetCameraUp(up);
2595  s_tools.instance->m_viewportParams.up = CCVector3d::fromArray(up);
2596 }
2597 
2599  const ecvViewportParameters& params) {
2600  ecvViewportParameters oldParams = s_tools.instance->m_viewportParams;
2601  s_tools.instance->m_viewportParams = params;
2602 
2603  if (oldParams.perspectiveView == params.perspectiveView) {
2604  if (oldParams.perspectiveView) {
2605  SetFov(params.fov_deg);
2606  } else {
2607  SetParallelScale(static_cast<double>(cloudViewer::DegreesToRadians(
2608  params.fov_deg)),
2609  0);
2610  }
2611  } else { // ignore fov_deg in different show mode
2612  // keep old show mode
2613  s_tools.instance->m_viewportParams.perspectiveView =
2614  oldParams.perspectiveView;
2615  }
2616 
2617  SetCameraClip(params.zNear, params.zFar);
2618  SetPivotPoint(params.getPivotPoint(), false, false);
2619  SetCameraPosition(params.getCameraCenter().u, params.focal.u, params.up.u);
2620 
2623  Deprecate3DLayer();
2624 
2625  emit s_tools.instance->baseViewMatChanged(
2626  s_tools.instance->m_viewportParams.viewMat);
2627  emit s_tools.instance->pivotPointChanged(
2628  s_tools.instance->m_viewportParams.getPivotPoint());
2629  emit s_tools.instance->cameraPosChanged(
2630  s_tools.instance->m_viewportParams.getCameraCenter());
2631  emit s_tools.instance->fovChanged(
2632  s_tools.instance->m_viewportParams.fov_deg);
2633  emit s_tools.instance->cameraParamChanged();
2634 }
2635 
2638  return s_tools.instance->m_viewportParams;
2639 }
2640 
2642  // Backup the camera center before entering this mode!
2643  bool bubbleViewModeWasEnabled = s_tools.instance->m_bubbleViewModeEnabled;
2644  if (!s_tools.instance->m_bubbleViewModeEnabled && state) {
2645  s_tools.instance->m_preBubbleViewParameters =
2646  s_tools.instance->m_viewportParams;
2647  }
2648 
2649  if (state) {
2650  // bubble-view mode = viewer-based perspective mode
2651  // setPerspectiveState must be called first as it
2652  // automatically deactivates bubble-view mode!
2653  SetPerspectiveState(true, false);
2654 
2655  s_tools.instance->m_bubbleViewModeEnabled = true;
2656 
2657  // when entering this mode, we reset the f.o.v.
2658  s_tools.instance->m_bubbleViewFov_deg =
2659  0.0f; // to trick the signal emission mechanism
2660  SetBubbleViewFov(90.0f);
2661  } else if (bubbleViewModeWasEnabled) {
2662  s_tools.instance->m_bubbleViewModeEnabled = false;
2664  s_tools.instance->m_preBubbleViewParameters.perspectiveView,
2665  s_tools.instance->m_preBubbleViewParameters.objectCenteredView);
2666 
2667  // when leaving this mode, we restore the original camera center
2668  SetViewportParameters(s_tools.instance->m_preBubbleViewParameters);
2669  }
2670 }
2671 
2673  if (fov_deg < FLT_EPSILON || fov_deg > 180.0f) return;
2674 
2675  if (fov_deg != s_tools.instance->m_bubbleViewFov_deg) {
2676  s_tools.instance->m_bubbleViewFov_deg = fov_deg;
2677 
2678  if (s_tools.instance->m_bubbleViewModeEnabled) {
2681  Deprecate3DLayer();
2682  emit s_tools.instance->fovChanged(
2683  s_tools.instance->m_bubbleViewFov_deg);
2684  emit s_tools.instance->cameraParamChanged();
2685  }
2686  }
2687 }
2688 
2689 void ecvDisplayTools::SetPixelSize(float pixelSize) {
2690  if (s_tools.instance->m_viewportParams.pixelSize != pixelSize) {
2691  s_tools.instance->m_viewportParams.pixelSize = pixelSize;
2692  }
2695  Deprecate3DLayer();
2696 }
2697 
2698 void ecvDisplayTools::SetZoom(float value) {
2699  // zoom should be avoided in bubble-view mode
2700  assert(!s_tools.instance->m_bubbleViewModeEnabled);
2701 
2702  if (value < CC_GL_MIN_ZOOM_RATIO)
2703  value = CC_GL_MIN_ZOOM_RATIO;
2704  else if (value > CC_GL_MAX_ZOOM_RATIO)
2705  value = CC_GL_MAX_ZOOM_RATIO;
2706 
2707  if (s_tools.instance->m_viewportParams.zoom != value) {
2708  s_tools.instance->m_viewportParams.zoom = value;
2711  // Deprecate3DLayer();
2712  }
2713 }
2714 
2715 void ecvDisplayTools::UpdateZoom(float zoomFactor) {
2716  // no 'zoom' in viewer based perspective
2717  assert(!s_tools.instance->m_viewportParams.perspectiveView);
2718 
2719  if (zoomFactor > 0.0f && zoomFactor != 1.0f) {
2720  SetZoom(s_tools.instance->m_viewportParams.zoom * zoomFactor);
2721  }
2722 }
2723 
2724 void ecvDisplayTools::SetPickingMode(PICKING_MODE mode /*=DEFAULT_PICKING*/) {
2725  // is the picking mode locked?
2726  if (s_tools.instance->m_pickingModeLocked) {
2727  if ((mode != s_tools.instance->m_pickingMode) &&
2728  (mode != DEFAULT_PICKING))
2730  "[ecvDisplayTools::setPickingMode] Picking mode is locked! "
2731  "Can't change it...");
2732  return;
2733  }
2734 
2735  switch (mode) {
2736  case DEFAULT_PICKING:
2737  mode = ENTITY_PICKING;
2738  case NO_PICKING:
2739  case ENTITY_PICKING:
2740  GetCurrentScreen()->setCursor(QCursor(Qt::ArrowCursor));
2741  break;
2744  case TRIANGLE_PICKING:
2745  case POINT_PICKING:
2746  GetCurrentScreen()->setCursor(QCursor(Qt::PointingHandCursor));
2747  break;
2748  default:
2749  break;
2750  }
2751 
2752  s_tools.instance->m_pickingMode = mode;
2753 
2754  // CVLog::Warning(QString("[%1] Picking mode set to: ").arg(m_uniqueID) +
2755  // ToString(m_pickingMode));
2756 }
2757 
2759  return s_tools.instance->m_pickingMode;
2760 }
2761 
2763  s_tools.instance->m_pickingModeLocked = state;
2764 }
2765 
2767  return s_tools.instance->m_pickingModeLocked;
2768 }
2769 
2771  if (!s_tools.instance->m_viewportParams.perspectiveView) {
2772  return static_cast<double>(
2773  s_tools.instance->m_viewportParams.pixelSize /
2774  s_tools.instance->m_viewportParams.zoom);
2775  }
2776 
2777  int minScreenDim = std::min(s_tools.instance->m_glViewport.width(),
2778  s_tools.instance->m_glViewport.height());
2779  if (minScreenDim <= 0) return 1.0;
2780 
2781  // Camera center to pivot vector
2782  double zoomEquivalentDist =
2783  (s_tools.instance->m_viewportParams.getCameraCenter() -
2784  s_tools.instance->m_viewportParams.getPivotPoint())
2785  .norm();
2786 
2787  double currentFov_deg = static_cast<double>(GetFov());
2788  return zoomEquivalentDist *
2790  std::min(currentFov_deg, 75.0))) /
2791  minScreenDim; // tan(75) = 3.73 (then it quickly increases!)
2792 }
2793 
2795  return s_tools.instance->m_allowRectangularEntityPicking;
2796 }
2797 
2799  s_tools.instance->m_allowRectangularEntityPicking = state;
2800 }
2801 
2803  // is the pivot really going to be drawn?
2804  if (state && !s_tools.instance->m_pivotSymbolShown &&
2805  s_tools.instance->m_viewportParams.objectCenteredView &&
2806  s_tools.instance->m_pivotVisibility != PIVOT_HIDE) {
2808  Deprecate3DLayer();
2809  }
2810 
2811  s_tools.instance->m_pivotSymbolShown = state;
2812 }
2813 
2815  return GetOptimizedFontSize(
2816  s_tools.instance->m_captureMode.enabled
2817  ? FontSizeModifier(
2818  GetDisplayParameters().defaultFontSize,
2819  s_tools.instance->m_captureMode.zoomFactor)
2820  : GetDisplayParameters().defaultFontSize);
2821 }
2822 
2824  return GetOptimizedFontSize(
2825  s_tools.instance->m_captureMode.enabled
2826  ? FontSizeModifier(
2827  GetDisplayParameters().labelFontSize,
2828  s_tools.instance->m_captureMode.zoomFactor)
2829  : GetDisplayParameters().labelFontSize);
2830 }
2831 
2833  QFont font = s_tools.instance->m_font;
2834  font.setPointSize(GetLabelFontPointSize());
2835  return font;
2836 }
2837 
2839 #ifdef CV_WINDOWS
2840  POINT lpPoint;
2841  POINT oldlpPoint;
2842  QPoint globalOldPoint = QCursor::pos();
2843  oldlpPoint.x = globalOldPoint.x();
2844  oldlpPoint.y = globalOldPoint.y();
2845 
2846  QRect screenRect = GetScreenRect();
2847  QPoint clickPos = screenRect.center();
2848  lpPoint.x = clickPos.x();
2849  lpPoint.y = clickPos.y();
2850 
2851  SetCursorPos(lpPoint.x, lpPoint.y);
2852  mouse_event(
2853  MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE, 0,
2854  0, 0, 0);
2855  Sleep(20);
2856  SetCursorPos(oldlpPoint.x, oldlpPoint.y);
2857 #else
2858  CVLog::Warning("only supported in windows!");
2859 #endif
2860 
2861  if (GetCurrentScreen()) {
2862  GetCurrentScreen()->setFocus();
2863  if (GetCurrentScreen()->parentWidget()) {
2864  GetCurrentScreen()->parentWidget()->setFocus();
2865  }
2866  }
2867 }
2868 
2870  s_tools.instance->m_shouldBeRefreshed = true;
2871 
2874 }
2875 
2876 void ecvDisplayTools::RefreshDisplay(bool only2D /*=false*/,
2877  bool forceRedraw /* = true*/) {
2878  if (s_tools.instance->m_shouldBeRefreshed) {
2879  RedrawDisplay(only2D, forceRedraw);
2880  }
2881 }
2882 
2883 void ecvDisplayTools::RedrawDisplay(bool only2D /*=false*/,
2884  bool forceRedraw /* = true*/) {
2885  // visual traces
2886  if (s_tools.instance->m_showDebugTraces) {
2887  // clear history
2888  RemoveWidgets(
2890  if (!s_tools.instance->m_diagStrings.isEmpty()) {
2891  QStringList::iterator it = s_tools.instance->m_diagStrings.begin();
2892  while (it != s_tools.instance->m_diagStrings.end()) {
2893  // no more valid? we delete the message
2895  it = s_tools.instance->m_diagStrings.erase(it);
2896  }
2897  }
2898 
2899  s_tools.instance->m_diagStrings
2900  << QString("only2D : %1").arg(only2D ? "true" : "false");
2901  s_tools.instance->m_diagStrings
2902  << QString("ForceRedraw : %1")
2903  .arg(forceRedraw ? "true" : "false");
2904  } else {
2905  RemoveWidgets(
2907  if (!s_tools.instance->m_diagStrings.isEmpty()) {
2908  QStringList::iterator it = s_tools.instance->m_diagStrings.begin();
2909  while (it != s_tools.instance->m_diagStrings.end()) {
2910  // no more valid? we delete the message
2912  it = s_tools.instance->m_diagStrings.erase(it);
2913  }
2914  }
2915  }
2916 
2917  CheckIfRemove();
2918  if (s_tools.instance->m_removeAllFlag) {
2919  Update();
2920  return;
2921  }
2922 
2923  // we update font size (for text display)
2925 
2926  if (!only2D) {
2927  // force the 3D layer to be redrawn
2928  Deprecate3DLayer();
2929  }
2930 
2931  bool drawBackground = false;
2932  bool draw3DPass = false;
2933  bool drawForeground = true;
2934  bool draw3DCross = GetDisplayParameters().displayCross;
2935 
2936  // here are all the reasons for which we would like to update the main 3D
2937  // layer
2938  if (s_tools.instance->m_updateFBO ||
2939  s_tools.instance->m_captureMode.enabled) {
2940  // we must update the FBO (or display without FBO)
2941  drawBackground = true;
2942  draw3DPass = true;
2943  }
2944 
2945  // context initialization
2946  CC_DRAW_CONTEXT CONTEXT;
2947  GetContext(CONTEXT);
2948 
2949  // clean the outdated messages
2950  {
2951  std::list<MessageToDisplay>::iterator it =
2952  s_tools.instance->m_messagesToDisplay.begin();
2953  qint64 currentTime_sec = s_tools.instance->m_timer.elapsed() / 1000;
2954  // CVLog::PrintDebug(QString("[paintGL] Current time:
2955  // %1.").arg(currentTime_sec));
2956 
2957  while (it != s_tools.instance->m_messagesToDisplay.end()) {
2958  // no more valid? we delete the message
2959  if (it->messageValidity_sec < currentTime_sec) {
2961  it->message));
2962  it = s_tools.instance->m_messagesToDisplay.erase(it);
2963  } else {
2964  ++it;
2965  }
2966  }
2967  }
2968 
2969  // backup the current viewport
2970  QRect originViewport = s_tools.instance->m_glViewport;
2971  bool modifiedViewport = false;
2972 
2973  /******************/
2974  /*** BACKGROUND ***/
2975  /******************/
2976  // shall we clear the background (depth and/or color)
2977  if (drawBackground) {
2978  if (s_tools.instance->m_showDebugTraces) {
2979  s_tools.instance->m_diagStrings << "draw background";
2980  }
2981 
2982  CONTEXT.clearColorLayer = true;
2983  CONTEXT.clearDepthLayer = true;
2984  DrawBackground(CONTEXT);
2985  }
2986 
2987  /*********************/
2988  /*** MAIN 3D LAYER ***/
2989  /*********************/
2990  if (draw3DPass) {
2991  if (s_tools.instance->m_showDebugTraces) {
2992  s_tools.instance->m_diagStrings << "draw 3D";
2993  }
2994 
2995  CONTEXT.forceRedraw = forceRedraw;
2996  Draw3D(CONTEXT);
2997  }
2998 
2999  // display traces
3000  if (s_tools.instance->m_showDebugTraces) {
3001  if (!s_tools.instance->m_diagStrings.isEmpty()) {
3002  QFont font = GetTextDisplayFont();
3003  int font_size = font.pointSize();
3004  QFontMetrics fm(font);
3005 
3006  int x = s_tools.instance->m_glViewport.width() / 2 - 100;
3007  int margin = font_size / 2;
3008  int y = margin;
3009 
3010  // draw black background
3011  {
3012  int height = (s_tools.instance->m_diagStrings.size() + 1) *
3013  (fm.height() + margin);
3015  DEBUG_LAYER_ID);
3016  param.color = ecvColor::dark;
3017  param.color.a = 0.5f;
3018  param.rect = QRect(
3019  x, s_tools.instance->m_glViewport.height() - y - height,
3020  200, height);
3021  DrawWidgets(param, true);
3022  }
3023  y += margin;
3024  for (const QString& str : s_tools.instance->m_diagStrings) {
3025  RenderText(x + font_size, y + font_size, str, font,
3027  y += fm.height() + margin;
3028  }
3029  }
3030  }
3031 
3032  // restore viewport if necessary
3033  if (modifiedViewport) {
3034  // correction for HD screens
3035  SetGLViewport(originViewport);
3036  CONTEXT.glW = originViewport.width();
3037  CONTEXT.glH = originViewport.height();
3038  modifiedViewport = false;
3039  }
3040 
3041  if (drawBackground || draw3DCross) {
3042  s_tools.instance->m_updateFBO = false;
3043  }
3044 
3045  /******************/
3046  /*** FOREGROUND ***/
3047  /******************/
3048  if (drawForeground) {
3049  DrawForeground(CONTEXT);
3050  }
3051 
3052  s_tools.instance->m_shouldBeRefreshed = false;
3053 
3054  if (false && s_tools.instance->m_autoPickPivotAtCenter &&
3055  !s_tools.instance->m_mouseMoved &&
3056  s_tools.instance->m_autoPivotCandidate.norm2d() != 0.0) {
3057  SetPivotPoint(s_tools.instance->m_autoPivotCandidate, true, false);
3058  }
3059 
3060  // update canvas
3061  UpdateScreen();
3062 }
3063 
3064 void ecvDisplayTools::SetGLViewport(const QRect& rect) {
3065  const int retinaScale = GetDevicePixelRatio();
3066  s_tools.instance->m_glViewport =
3067  QRect(rect.left() * retinaScale, rect.top() * retinaScale,
3068  rect.width() * retinaScale, rect.height() * retinaScale);
3070 }
3071 
3073 
3075 
3076 void ecvDisplayTools::Draw3D(CC_DRAW_CONTEXT& CONTEXT) {
3078  if (s_tools.instance->m_interactionFlags & INTERACT_TRANSFORM_ENTITIES) {
3080  }
3081 
3082  /****************************************/
3083  /**** PASS: 3D/FOREGROUND/LIGHT ****/
3084  /****************************************/
3085  if (s_tools.instance->m_customLightEnabled ||
3086  s_tools.instance->m_sunLightEnabled) {
3087  CONTEXT.drawingFlags |= CC_LIGHT_ENABLED;
3088 
3089  // we enable absolute sun light (if activated)
3090  if (s_tools.instance->m_sunLightEnabled) {
3091  // glEnableSunLight();
3092  }
3093  }
3094 
3095  // we draw 3D entities
3096  if (s_tools.instance->m_globalDBRoot) {
3097  s_tools.instance->m_globalDBRoot->draw(CONTEXT);
3098  }
3099 
3100  if (s_tools.instance->m_winDBRoot) {
3101  s_tools.instance->m_winDBRoot->draw(CONTEXT);
3102  }
3103 
3104 #if 0
3105  //do this before drawing the pivot!
3106  if (s_tools.instance->m_autoPickPivotAtCenter)
3107  {
3108  CCVector3d P;
3109  if (GetClick3DPos(s_tools.instance->m_glViewport.width() / 2, s_tools.instance->m_glViewport.height() / 2, P))
3110  {
3111  s_tools.instance->m_autoPivotCandidate = P;
3112  }
3113  }
3114 #endif
3115 
3116  if (s_tools.instance->m_globalDBRoot &&
3117  s_tools.instance->m_globalDBRoot->getChildrenNumber()) {
3118  // draw pivot
3119  // DrawPivot();
3120  }
3121 }
3122 
3123 void ecvDisplayTools::HideShowEntities(const QStringList& viewIDs,
3124  ENTITY_TYPE hideShowEntityType,
3125  bool visibility) {
3127  context.hideShowEntityType = hideShowEntityType;
3128  context.visible = visibility;
3129  for (const QString& removeViewId : viewIDs) {
3130  context.viewID = removeViewId;
3132  }
3133 }
3134 
3135 bool ecvDisplayTools::HideShowEntities(const ccHObject* obj, bool visible) {
3136  if (!obj || !ecvDisplayTools::GetCurrentScreen()) {
3137  return false;
3138  }
3140  context.visible = visible;
3141  context.viewID = obj->getViewId();
3142  context.hideShowEntityType = obj->getEntityType();
3144  return true;
3145 }
3146 
3148  if (!obj || !ecvDisplayTools::GetCurrentScreen()) {
3149  return;
3150  }
3151 
3153  context.removeViewID = obj->getViewId();
3154  context.removeEntityType = obj->getEntityType();
3156 }
3157 
3158 void ecvDisplayTools::RemoveEntities(const QStringList& viewIDs,
3159  ENTITY_TYPE removeEntityType) {
3161  context.removeEntityType = removeEntityType;
3162  for (const QString& removeViewId : viewIDs) {
3163  context.removeViewID = removeViewId;
3165  }
3166 }
3167 
3169  CONTEXT.drawingFlags = CC_DRAW_2D;
3170  if (s_tools.instance->m_interactionFlags & INTERACT_TRANSFORM_ENTITIES) {
3172  }
3173 
3174  // clear background
3175  {
3176  if (CONTEXT.clearDepthLayer) {
3177  }
3178  if (CONTEXT.clearColorLayer) {
3179  const ecvGui::ParamStruct& displayParams = GetDisplayParameters();
3180  if (displayParams.drawBackgroundGradient) {
3181  // draw the default gradient color background
3182  // we use the default background color for gradient start
3183  const ecvColor::Rgbub& bkgCol2 =
3185 
3186  // and the inverse of the text color for gradient stop
3188  bkgCol1.r = 255 - GetDisplayParameters().textDefaultCol.r;
3189  bkgCol1.g = 255 - GetDisplayParameters().textDefaultCol.g;
3190  bkgCol1.b = 255 - GetDisplayParameters().textDefaultCol.b;
3191  CONTEXT.backgroundCol = bkgCol1;
3192  CONTEXT.backgroundCol2 = bkgCol2;
3193  CONTEXT.drawBackgroundGradient = true;
3194 
3195  } else {
3196  // use plain color as specified by the user
3197  const ecvColor::Rgbub& bkgCol = displayParams.backgroundCol;
3198  CONTEXT.backgroundCol = bkgCol;
3199  CONTEXT.backgroundCol2 = bkgCol;
3200  CONTEXT.drawBackgroundGradient = false;
3201  }
3202 
3203  s_tools.instance->setBackgroundColor(CONTEXT);
3204  }
3205  }
3206 }
3207 
3209  /****************************************/
3210  /**** PASS: 2D/FOREGROUND/NO LIGHT ****/
3211  /****************************************/
3212 
3214  if (s_tools.instance->m_interactionFlags & INTERACT_TRANSFORM_ENTITIES) {
3216  }
3217 
3218  // we draw 2D entities
3219  if (s_tools.instance->m_globalDBRoot)
3220  s_tools.instance->m_globalDBRoot->draw(CONTEXT);
3221  if (s_tools.instance->m_winDBRoot)
3222  s_tools.instance->m_winDBRoot->draw(CONTEXT);
3223 
3224  // current displayed scalar field color ramp (if any)
3226 
3227  s_tools.instance->m_clickableItems.clear();
3228 
3229  /*** overlay entities ***/
3230  if (s_tools.instance->m_displayOverlayEntities) {
3231  // const ecvColor::Rgbub& textCol =
3232  // GetDisplayParameters().textDefaultCol;
3233 
3234  if (!s_tools.instance->m_captureMode.enabled ||
3235  s_tools.instance->m_captureMode.renderOverlayItems) {
3236  // scale: only in ortho mode
3237  if (!s_tools.instance->m_viewportParams.perspectiveView) {
3238  SetScaleBarVisible(true);
3239  } else {
3240  SetScaleBarVisible(false);
3241  }
3242  UpdateScreen();
3243  }
3244 
3245  if (!s_tools.instance->m_captureMode.enabled) {
3246  int yStart = 0;
3247 
3248  // current messages (if valid)
3249  if (!s_tools.instance->m_messagesToDisplay.empty()) {
3250  QFont font = s_tools.instance->m_font;
3251  QFontMetrics fm(font);
3252  int margin = fm.height() / 4;
3253  int ll_currentHeight =
3254  s_tools.instance->m_glViewport.height() - 10;
3255  int uc_currentHeight = 10;
3256 
3257  for (const auto& message :
3258  s_tools.instance->m_messagesToDisplay) {
3259  switch (message.position) {
3260  case LOWER_LEFT_MESSAGE: {
3261  RenderText(10, ll_currentHeight, message.message,
3262  font);
3263  int messageHeight = fm.height();
3264  ll_currentHeight -= (messageHeight + margin);
3265  } break;
3266  case UPPER_CENTER_MESSAGE: {
3267  QRect rect = fm.boundingRect(message.message);
3268  int x = (s_tools.instance->m_glViewport.width() -
3269  rect.width()) /
3270  2;
3271  int y = uc_currentHeight + rect.height();
3272  RenderText(x, y, message.message, font);
3273  uc_currentHeight += (rect.height() + margin);
3274  } break;
3275  case SCREEN_CENTER_MESSAGE: {
3276  QFont newFont(font);
3277  int fontSize = GetOptimizedFontSize(12);
3278  newFont.setPointSize(fontSize);
3279  QRect rect = QFontMetrics(newFont).boundingRect(
3280  message.message);
3281  RenderText(
3282  (s_tools.instance->m_glViewport.width() -
3283  rect.width()) /
3284  2,
3285  (s_tools.instance->m_glViewport.height() -
3286  rect.height()) /
3287  2,
3288  message.message, newFont);
3289  } break;
3290  }
3291  }
3292  }
3293 
3294  // hot-zone
3295  { s_tools.instance->DrawClickableItems(0, yStart); }
3296  }
3297  }
3298 }
3299 
3301  // we get the other selected labels as well!
3302  ccHObject::Container labels;
3304 
3305  for (auto& label : labels) {
3306  // Warning: cc2DViewportLabel is also a kind of 'CV_TYPES::LABEL_2D'!
3307  if (label->isA(CV_TYPES::LABEL_2D) && label->isVisible()) {
3308  cc2DLabel* l = static_cast<cc2DLabel*>(label);
3309  if (!l || (l->isDisplayedIn2D() && !l->isPointLegendDisplayed()))
3310  continue;
3311 
3315  }
3316  }
3317 }
3318 
3319 void ecvDisplayTools::Update2DLabel(bool immediateUpdate /* = false*/) {
3320  // we get the other selected labels as well!
3321 
3322  s_tools.instance->m_activeItems.clear();
3323  ccHObject::Container labels;
3325 
3326  for (auto& label : labels) {
3327  // Warning: cc2DViewportLabel is also a kind of 'CV_TYPES::LABEL_2D'!
3328  if (label->isA(CV_TYPES::LABEL_2D) && label->isVisible()) {
3330  if (!l || (l->isDisplayedIn2D() && !l->isPointLegendDisplayed()))
3331  continue;
3332 
3333  s_tools.instance->m_activeItems.push_back(l);
3334  if (immediateUpdate) {
3338  }
3339  } else if (label->isA(CV_TYPES::VIEWPORT_2D_LABEL)) {
3341  if (!l) continue;
3342  l->clear2Dviews();
3343  }
3344  }
3345 }
3346 
3348  QString id = s_tools.instance->pick2DLabel(x, y);
3349 
3350  // we get the other selected labels as well!
3351  s_tools.instance->m_activeItems.clear();
3352  if (!id.isEmpty()) {
3353  ccHObject::Container labels;
3355  for (auto& label : labels) {
3356  // Warning: cc2DViewportLabel is also a kind of
3357  // 'CV_TYPES::LABEL_2D'!
3358  if (label->isA(CV_TYPES::LABEL_2D) && label->isVisible()) {
3360  if (l->getViewId().compare(id) == 0) {
3361  s_tools.instance->m_activeItems.push_back(l);
3362  }
3363  }
3364  }
3365  }
3366 }
3367 
3369  CV_CLASS_ENUM type) {
3370  if (s_tools.instance->m_globalDBRoot)
3371  s_tools.instance->m_globalDBRoot->filterChildren(labels, true, type);
3372  if (s_tools.instance->m_winDBRoot)
3373  s_tools.instance->m_winDBRoot->filterChildren(labels, true, type);
3374 }
3375 
3377  int x,
3378  int y,
3379  const QString& str,
3380  const QFont& font /*=QFont()*/,
3381  const ecvColor::Rgbub& color /* = ecvColor::defaultLabelBkgColor*/,
3382  const QString& id) {
3384  // for T2D
3385  if (id.isEmpty()) {
3386  context.viewID = str;
3387  } else {
3388  context.viewID = id;
3389  }
3390 
3391  context.textParam.text = str;
3392  context.textParam.display3D = false;
3393  context.textParam.font = font;
3394  context.textParam.font.setPointSize(font.pointSize());
3395  // QRect screen = QGuiApplication::primaryScreen()->geometry();
3396 
3397  context.textDefaultCol = color;
3398  if (context.textParam.display3D) {
3399  context.textParam.textScale = GetPlatformAwareDPIScale();
3400  CCVector3d input3D(x, s_tools.instance->m_glViewport.height() - y, 0);
3401  CCVector3d output2D;
3402  ToWorldPoint(input3D, output2D);
3403  context.textParam.textPos.x = output2D.x;
3404  context.textParam.textPos.y = output2D.y;
3405  context.textParam.textPos.z = output2D.z;
3406  } else {
3407  context.textParam.textPos.x = x;
3408  context.textParam.textPos.y =
3409  s_tools.instance->m_glViewport.height() - y;
3410  context.textParam.textPos.z = 0;
3411  }
3413 }
3414 
3416  double x,
3417  double y,
3418  double z,
3419  const QString& str,
3420  const QFont& font /*=QFont()*/,
3421  const ecvColor::Rgbub& color /* = ecvColor::defaultLabelBkgColor*/,
3422  const QString& id) {
3423  // get the actual viewport / matrices
3424  ccGLCameraParameters camera;
3428 
3429  CCVector3d Q2D(0, 0, 0);
3430  if (camera.project(CCVector3d(x, y, z), Q2D)) {
3431  Q2D.y = s_tools.instance->m_glViewport.height() - 1 - Q2D.y;
3432  RenderText(Q2D.x, Q2D.y, str, font, color, id);
3433  }
3434 }
3435 
3436 void ecvDisplayTools::Display3DLabel(const QString& str,
3437  const CCVector3& pos3D,
3438  const ecvColor::Rgbub* color /*=nullptr*/,
3439  const QFont& font /*=QFont()*/) {
3440  ecvColor::Rgbub col(color ? color->rgb
3441  : GetDisplayParameters().textDefaultCol.rgb);
3442  RenderText(pos3D.x, pos3D.y, pos3D.z, str, font, col);
3443 }
3444 
3446  const QString& text,
3447  int x,
3448  int y,
3449  unsigned char align /*=ALIGN_HLEFT|ALIGN_VTOP*/,
3450  float bkgAlpha /*=0*/,
3451  const unsigned char* rgbColor /*=0*/,
3452  const QFont* font /*=0*/,
3453  const QString& id /*=""*/) {
3454  int x2 = x;
3455  int y2 = s_tools.instance->m_glViewport.height() - 1 - y;
3456 
3457  // actual text color
3458  const unsigned char* col =
3459  (rgbColor ? rgbColor : GetDisplayParameters().textDefaultCol.rgb);
3460 
3461  QFont realFont = (font ? *font : s_tools.instance->m_font);
3462  QFont textFont = realFont;
3463  QFontMetrics fm(textFont);
3464  int margin = fm.height() / 4;
3465 
3466  if (align != ALIGN_DEFAULT || bkgAlpha != 0.0f) {
3467  QRect rect = fm.boundingRect(text);
3468 
3469  // text alignment
3470  if (align & ALIGN_HMIDDLE)
3471  x2 -= rect.width() / 2;
3472  else if (align & ALIGN_HRIGHT)
3473  x2 -= rect.width();
3474  if (align & ALIGN_VMIDDLE)
3475  y2 += rect.height() / 2;
3476  else if (align & ALIGN_VBOTTOM)
3477  y2 += rect.height();
3478 
3479  // background is not totally transparent
3480  if (bkgAlpha != 0.0f) {
3481  // inverted color with a bit of transparency
3482  const float invertedCol[4] = {(255 - col[0]) / 255.0f,
3483  (255 - col[0]) / 255.0f,
3484  (255 - col[0]) / 255.0f, bkgAlpha};
3485 
3486  // int xB = x2 - s_tools.instance->m_glViewport.width() / 2;
3487  // int yB = s_tools.instance->m_glViewport.height() / 2 - y2;
3488  // yB += margin / 2; //empirical compensation
3489 
3490  int xB = x2;
3491  int yB = s_tools.instance->m_glViewport.height() - y2;
3492 
3494  param.text = text;
3495 
3496  if (id.isEmpty()) {
3497  param.viewID = text;
3498  RemoveWidgets(param);
3499  }
3500 
3501  param.color.r = invertedCol[0];
3502  param.color.g = invertedCol[1];
3503  param.color.b = invertedCol[2];
3504  param.color.a = invertedCol[3];
3505  param.rect =
3506  QRect(xB - margin, yB - margin, rect.width() + 2 * margin,
3507  static_cast<int>(rect.height() + 1.5 * margin));
3508 
3509 #ifdef Q_OS_MAC
3510  // fix name3d background issues on mac
3511  param.rect.setWidth(param.rect.width() * 2);
3512  // Note: should be moved to the top of the screen (equal to move
3513  // bottom) in GL coordinates.
3514  param.rect.moveTop(std::min(s_tools.instance->m_glViewport.height(),
3515  param.rect.y() + 2 * margin));
3516 #endif
3517 
3518  DrawWidgets(param, true);
3519  }
3520  }
3521 
3522  if (align & ALIGN_VBOTTOM)
3523  y2 -= margin; // empirical compensation
3524  else if (align & ALIGN_VMIDDLE)
3525  y2 -= margin / 2; // empirical compensation
3526 
3527  ecvColor::Rgbub textColor(col);
3528  RenderText(x2, y2, text, realFont, textColor, id);
3529 }
3530 
3532  const QString& id,
3533  int x,
3534  int y,
3535  int w,
3536  int h,
3537  unsigned char alpha /*=255*/) {
3539  param.image = image;
3540  param.opacity = alpha / 255.0f;
3541  param.rect = QRect(x, y, w, h);
3542  DrawWidgets(param, true);
3543 }
3544 
3547  s_tools.instance->m_hotZone->bbv_label));
3549  s_tools.instance->m_hotZone->fs_label));
3551  s_tools.instance->m_hotZone->psi_label));
3553  s_tools.instance->m_hotZone->lsi_label));
3556 }
3557 
3558 void ecvDisplayTools::DrawClickableItems(int xStart0, int& yStart) {
3559  const static char* CLICKED_ITEMS = "clicked_items";
3560  // we init the necessary parameters the first time we need them
3561  if (!s_tools.instance->m_hotZone) {
3562  s_tools.instance->m_hotZone =
3564  } else if (GetPlatformAwareDPIScale() !=
3565  s_tools.instance->m_hotZone
3566  ->pixelDeviceRatio) // the device pixel ratio has
3567  // changed (happens when changing
3568  // screen for instance)
3569  {
3570  s_tools.instance->m_hotZone->updateInternalVariables(
3572  }
3573 
3574  // remember the last position of the 'top corner'
3575  s_tools.instance->m_hotZone->topCorner =
3576  QPoint(xStart0, yStart) +
3577  QPoint(s_tools.instance->m_hotZone->margin,
3578  s_tools.instance->m_hotZone->margin);
3579 
3580  bool fullScreenEnabled = ExclusiveFullScreen();
3581 
3582  if (!s_tools.instance->m_clickableItemsVisible &&
3583  !s_tools.instance->m_bubbleViewModeEnabled && !fullScreenEnabled) {
3584  ClearBubbleView();
3585  // nothing to do
3586  return;
3587  }
3588 
3589  //"exit" icon
3590  // static const QImage c_exitIcon =
3591  // QImage(":/Resources/images/ecvExit.png").mirrored();
3592  int fullW = s_tools.instance->m_glViewport.width();
3593  int fullH = s_tools.instance->m_glViewport.height();
3594 
3595  // clear history
3597 
3598  // draw semi-transparent background
3599  {
3600  QRect areaRect = s_tools.instance->m_hotZone->rect(
3601  s_tools.instance->m_clickableItemsVisible,
3602  s_tools.instance->m_bubbleViewModeEnabled, fullScreenEnabled);
3603  areaRect.translate(s_tools.instance->m_hotZone->topCorner);
3604 
3606  CLICKED_ITEMS);
3608  param.color.a = 210 / 255.0f;
3609  int x0 = areaRect.x();
3610  int y0 = fullH - areaRect.y() - areaRect.height();
3611  param.rect = QRect(x0, y0, areaRect.width(), areaRect.height());
3612  DrawWidgets(param, false);
3613  }
3614 
3615  yStart = s_tools.instance->m_hotZone->topCorner.y();
3616  int offset = 0;
3617 #ifdef Q_OS_MAC
3618  // fix the start of text vertically on macos
3619  offset = s_tools.instance->m_hotZone->margin / 3;
3620 #endif
3621  int iconSize = s_tools.instance->m_hotZone->iconSize;
3622 
3623  if (fullScreenEnabled) {
3624  int xStart = s_tools.instance->m_hotZone->topCorner.x();
3625 
3626  // label
3627  RenderText(xStart,
3628  yStart + offset +
3629  s_tools.instance->m_hotZone->yTextBottomLineShift,
3630  s_tools.instance->m_hotZone->fs_label,
3631  s_tools.instance->m_hotZone->font,
3632  ecvColor::defaultLabelBkgColor, CLICKED_ITEMS);
3633 
3634  // icon
3635  xStart += s_tools.instance->m_hotZone->fs_labelRect.width() +
3636  s_tools.instance->m_hotZone->margin;
3637 
3638 #ifdef Q_OS_MAC
3639  // fix the start of icon on mac
3640  xStart += s_tools.instance->m_hotZone->margin * 4;
3641 #endif
3642  //"full-screen" icon
3643  {
3644  int x0 = xStart;
3645  int y0 = fullH - (yStart + iconSize);
3647  CLICKED_ITEMS);
3648  param.color = ecvColor::FromRgba(ecvColor::ored);
3649  param.rect = QRect(x0, y0, iconSize + offset, iconSize);
3650  DrawWidgets(param, false);
3651 
3652  WIDGETS_PARAMETER texParam(WIDGETS_TYPE::WIDGET_T2D, CLICKED_ITEMS);
3653  texParam.color = ecvColor::bright;
3654  texParam.text = "Exit";
3655  texParam.rect =
3656  QRect(x0, fullH - (yStart + offset / 2 + 3 * iconSize / 4),
3657  iconSize, iconSize);
3658  texParam.fontSize = s_tools.instance->m_hotZone->font.pointSize();
3659  DrawWidgets(texParam, false);
3660  s_tools.instance->m_clickableItems.emplace_back(
3662  QRect(xStart, yStart, iconSize, iconSize));
3663  xStart += iconSize;
3664  }
3665 
3666  yStart += iconSize;
3667  yStart += s_tools.instance->m_hotZone->margin;
3668  }
3669 
3670  if (s_tools.instance->m_bubbleViewModeEnabled) {
3671  int xStart = s_tools.instance->m_hotZone->topCorner.x();
3672 
3673  // label
3674  RenderText(xStart,
3675  yStart + offset +
3676  s_tools.instance->m_hotZone->yTextBottomLineShift,
3677  s_tools.instance->m_hotZone->bbv_label,
3678  s_tools.instance->m_hotZone->font);
3679 
3680  // icon
3681  xStart += s_tools.instance->m_hotZone->bbv_labelRect.width() +
3682  s_tools.instance->m_hotZone->margin;
3683 #ifdef Q_OS_MAC
3684  // fix the start of icon on mac
3685  xStart += s_tools.instance->m_hotZone->margin * 4;
3686 #endif
3687 
3688  //"exit" icon
3689  {
3690  s_tools.instance->m_clickableItems.emplace_back(
3692  QRect(xStart, yStart, s_tools.instance->m_hotZone->iconSize,
3693  s_tools.instance->m_hotZone->iconSize));
3694  xStart += s_tools.instance->m_hotZone->iconSize;
3695  }
3696 
3697  yStart += s_tools.instance->m_hotZone->iconSize;
3698  yStart += s_tools.instance->m_hotZone->margin;
3699  }
3700 
3701  if (s_tools.instance->m_clickableItemsVisible) {
3702  ecvColor::Rgb textColor =
3703  ecvColor::Rgb(s_tools.instance->m_hotZone->color);
3705  CLICKED_ITEMS);
3706  widgetParam.color = ecvColor::FromRgba(ecvColor::ogreen);
3708  CLICKED_ITEMS);
3709  sepParam.color = widgetParam.color;
3710  sepParam.color.a = 0.5f;
3711 
3712  // default point size
3713  {
3714  int xStart = s_tools.instance->m_hotZone->topCorner.x();
3715 
3716  RenderText(
3717  xStart,
3718  yStart + offset +
3719  s_tools.instance->m_hotZone->yTextBottomLineShift,
3720  s_tools.instance->m_hotZone->psi_label,
3721  s_tools.instance->m_hotZone->font, textColor,
3722  CLICKED_ITEMS);
3723 
3724  // icons
3725  xStart += s_tools.instance->m_hotZone->psi_labelRect.width() +
3726  s_tools.instance->m_hotZone->margin;
3727 #ifdef Q_OS_MAC
3728  // fix the start of icon on mac
3729  xStart += s_tools.instance->m_hotZone->margin * 4;
3730 #else
3731  // fix the start of icon on linux or windows
3732  xStart -= iconSize;
3733 #endif
3734  //"minus" icon
3735  {
3736  int x0 = xStart;
3737  int y0 = fullH - (yStart + iconSize / 2);
3738  widgetParam.rect = QRect(x0, y0, iconSize, iconSize / 4);
3739  DrawWidgets(widgetParam, false);
3740  s_tools.instance->m_clickableItems.emplace_back(
3742  QRect(xStart, yStart, iconSize, iconSize));
3743  xStart += iconSize;
3744  }
3745 
3746  // separator
3747  {
3748  sepParam.radius =
3749  s_tools.instance->m_viewportParams.defaultPointSize / 2;
3750  int x0 = xStart +
3751  s_tools.instance->m_hotZone
3752  ->margin /*s_tools.instance->m_hotZone->margin
3753  / 2*/
3754  ;
3755  int y0 = fullH - (yStart + iconSize / 2);
3756  sepParam.rect = QRect(x0, y0, iconSize, iconSize);
3757  DrawWidgets(sepParam, false);
3758  xStart += s_tools.instance->m_hotZone->margin * 2;
3759  }
3760 
3761  //"plus" icon
3762  {
3763  int x0 = xStart;
3764  int y0 = fullH - (yStart + iconSize / 2);
3765  widgetParam.rect = QRect(x0, y0, iconSize, iconSize / 4);
3766  DrawWidgets(widgetParam, false);
3767  x0 = xStart + 3 * iconSize / 8;
3768  y0 = fullH - (yStart + 7 * iconSize / 8);
3769  widgetParam.rect = QRect(x0, y0, iconSize / 4, iconSize);
3770  DrawWidgets(widgetParam, false);
3771 
3772  s_tools.instance->m_clickableItems.emplace_back(
3774  QRect(xStart, yStart, iconSize, iconSize));
3775  xStart += iconSize;
3776  }
3777 
3778  yStart += iconSize;
3779  yStart += s_tools.instance->m_hotZone->margin;
3780  }
3781 
3782  // default line size
3783  {
3784  int xStart = s_tools.instance->m_hotZone->topCorner.x();
3785 
3786  RenderText(
3787  xStart,
3788  yStart + offset +
3789  s_tools.instance->m_hotZone->yTextBottomLineShift,
3790  s_tools.instance->m_hotZone->lsi_label,
3791  s_tools.instance->m_hotZone->font, textColor,
3792  CLICKED_ITEMS);
3793 
3794  // icons
3795  xStart += s_tools.instance->m_hotZone->lsi_labelRect.width() +
3796  s_tools.instance->m_hotZone->margin;
3797 #ifdef Q_OS_MAC
3798  // fix the start of icon on mac
3799  xStart += s_tools.instance->m_hotZone->margin * 4;
3800 #else
3801  // fix the start of icon on linux or windows
3802  xStart -= iconSize;
3803 #endif
3804  //"minus" icon
3805  {
3806  int x0 = xStart;
3807  int y0 = fullH - (yStart + iconSize / 2);
3808  widgetParam.rect = QRect(x0, y0, iconSize, iconSize / 4);
3809  DrawWidgets(widgetParam, false);
3810 
3811  s_tools.instance->m_clickableItems.emplace_back(
3813  QRect(xStart, yStart, iconSize, iconSize));
3814  xStart += iconSize;
3815  }
3816 
3817  // separator
3818  {
3819  sepParam.radius =
3820  s_tools.instance->m_viewportParams.defaultLineWidth / 2;
3821  int x0 = xStart +
3822  s_tools.instance->m_hotZone
3823  ->margin /*s_tools.instance->m_hotZone->margin
3824  / 2*/
3825  ;
3826  int y0 = fullH - (yStart + iconSize / 2);
3827  sepParam.rect = QRect(x0, y0, iconSize, iconSize);
3828  DrawWidgets(sepParam, false);
3829  xStart += s_tools.instance->m_hotZone->margin * 2;
3830  }
3831 
3832  //"plus" icon
3833  {
3834  int x0 = xStart;
3835  int y0 = fullH - (yStart + iconSize / 2);
3836  widgetParam.rect = QRect(x0, y0, iconSize, iconSize / 4);
3837  DrawWidgets(widgetParam, false);
3838  x0 = xStart + 3 * iconSize / 8;
3839  y0 = fullH - (yStart + 7 * iconSize / 8);
3840  widgetParam.rect = QRect(x0, y0, iconSize / 4, iconSize);
3841  DrawWidgets(widgetParam, false);
3842 
3843  s_tools.instance->m_clickableItems.emplace_back(
3845  QRect(xStart, yStart, iconSize, iconSize));
3846  xStart += iconSize;
3847  }
3848 
3849  yStart += iconSize;
3850  yStart += s_tools.instance->m_hotZone->margin;
3851  }
3852  }
3853 }
3854 
3856  if (s_tools.instance->m_removeAllFlag) {
3858  context.removeEntityType = ENTITY_TYPE::ECV_ALL;
3860  SetRemoveAllFlag(false);
3861  } else if (s_tools.instance->m_removeFlag) {
3862  for (const removeInfo& rmInfo : s_tools.instance->m_removeInfos) {
3863  if (rmInfo.removeType == ENTITY_TYPE::ECV_NONE) continue;
3864  // octree and kdtree object has been deleted before
3865  if (rmInfo.removeType == ENTITY_TYPE::ECV_OCTREE) continue;
3866  if (rmInfo.removeType == ENTITY_TYPE::ECV_KDTREE) continue;
3867  if (rmInfo.removeType == ENTITY_TYPE::ECV_2DLABLE) continue;
3868  if (rmInfo.removeType == ENTITY_TYPE::ECV_SENSOR) continue;
3869 
3871  context.removeEntityType = rmInfo.removeType;
3872  context.removeViewID = rmInfo.removeId;
3874  RemoveBB(context);
3875  }
3876  s_tools.instance->m_removeFlag = false;
3877  }
3878 }
3879 
3881  context.removeEntityType = ENTITY_TYPE::ECV_SHAPE;
3882  context.removeViewID = QString("BBox-") + context.removeViewID;
3884 }
3885 
3886 void ecvDisplayTools::RemoveBB(const QString& viewId) {
3888  context.removeViewID = viewId;
3889  RemoveBB(context);
3890 }
3891 
3893  bool autoUpdate /* = true*/) {
3894  if (propertyParam.entity) {
3895  if (propertyParam.entity->isKindOf(CV_TYPES::PRIMITIVE)) {
3897  } else {
3898  propertyParam.entityType =
3899  ConvertToEntityType(propertyParam.entity->getClassID());
3900  }
3901 
3902  propertyParam.viewId = propertyParam.entity->getViewId();
3903  s_tools.instance->changeEntityProperties(propertyParam);
3904  if (autoUpdate) {
3905  UpdateScreen();
3906  }
3907  }
3908 }
3909 
3911  bool update /* = false*/) {
3912  ccHObject* entity = param.entity;
3913  int viewport = param.viewport;
3914  switch (param.type) {
3917  break;
3919  break;
3920 
3921  case WIDGETS_TYPE::WIDGET_T2D: {
3922  QFont textFont = s_tools.instance->m_font;
3923  const_cast<WIDGETS_PARAMETER*>(&param)->fontSize =
3924  textFont.pointSize();
3925 
3926  s_tools.instance->drawWidgets(param);
3927  } break;
3936  s_tools.instance->drawWidgets(param);
3937  break;
3939  if (param.lineWidget.valid) {
3940  s_tools.instance->drawWidgets(param);
3941  }
3942  break;
3944  // context initialization
3945  CC_DRAW_CONTEXT CONTEXT;
3946  GetContext(CONTEXT);
3947  ccPolyline* poly = ccHObjectCaster::ToPolyline(entity);
3948  if (poly->is2DMode()) {
3950  } else {
3952  }
3953 
3954  if (s_tools.instance->m_interactionFlags &
3957  }
3958  CONTEXT.defaultViewPort = viewport;
3959  poly->draw(CONTEXT);
3960  } break;
3962  s_tools.instance->drawWidgets(param);
3963  break;
3965  s_tools.instance->drawWidgets(param);
3966  break;
3968  break;
3969  default:
3970  break;
3971  }
3972 
3973  if (update) {
3974  UpdateScreen();
3975  }
3976 }
3977 
3979  bool update /* = false*/) {
3981  switch (param.type) {
3983  break;
3985  context.removeEntityType = ENTITY_TYPE::ECV_SHAPE;
3986  context.viewID = QString("BBox-") + param.viewID;
3988  } break;
3990  context.defaultViewPort = param.viewport;
3991  context.removeEntityType = ENTITY_TYPE::ECV_MESH;
3992  context.removeViewID = param.viewID;
3994  } break;
3997  context.defaultViewPort = param.viewport;
3998  context.removeEntityType = ENTITY_TYPE::ECV_LINES_3D;
3999  context.removeViewID = param.viewID;
4001  } break;
4003  context.removeEntityType = ENTITY_TYPE::ECV_CAPTION;
4004  context.defaultViewPort = param.viewport;
4005  context.removeViewID = param.viewID;
4007  } break;
4009  context.removeEntityType = ENTITY_TYPE::ECV_SCALAR_BAR;
4010  context.defaultViewPort = param.viewport;
4011  context.removeViewID = param.viewID;
4013  } break;
4015  context.defaultViewPort = param.viewport;
4016  context.removeEntityType = ENTITY_TYPE::ECV_SHAPE;
4017  context.removeViewID = param.viewID;
4019  } break;
4021  context.defaultViewPort = param.viewport;
4022  context.removeEntityType = ENTITY_TYPE::ECV_IMAGE;
4023  context.removeViewID = param.viewID;
4025  } break;
4027  context.defaultViewPort = param.viewport;
4028  context.removeEntityType = ENTITY_TYPE::ECV_MARK_POINT;
4029  context.removeViewID = param.viewID;
4031  } break;
4033  context.defaultViewPort = param.viewport;
4034  context.removeEntityType = ENTITY_TYPE::ECV_CIRCLE_2D;
4035  context.removeViewID = param.viewID;
4037  }
4039  context.defaultViewPort = param.viewport;
4040  context.removeEntityType = ENTITY_TYPE::ECV_TRIANGLE_2D;
4041  context.removeViewID = param.viewID;
4043  } break;
4045  context.defaultViewPort = param.viewport;
4046  context.removeEntityType = ENTITY_TYPE::ECV_POLYLINE_2D;
4047  context.removeViewID = param.viewID;
4049  } break;
4051  context.defaultViewPort = param.viewport;
4052  context.removeEntityType = ENTITY_TYPE::ECV_LINES_2D;
4053  context.removeViewID = param.viewID;
4055  } break;
4057  context.defaultViewPort = param.viewport;
4058  context.removeEntityType = ENTITY_TYPE::ECV_RECTANGLE_2D;
4059  context.removeViewID = param.viewID;
4061  } break;
4062  case WIDGETS_TYPE::WIDGET_T2D: {
4063  context.defaultViewPort = param.viewport;
4064  context.removeEntityType = ENTITY_TYPE::ECV_TEXT2D;
4065  context.removeViewID = param.viewID;
4067  } break;
4068  case WIDGETS_TYPE::WIDGET_T3D: {
4069  context.defaultViewPort = param.viewport;
4070  context.removeEntityType = ENTITY_TYPE::ECV_TEXT3D;
4071  context.removeViewID = param.viewID;
4073  } break;
4074  default:
4075  break;
4076  }
4077 
4078  if (update) {
4079  UpdateScreen();
4080  }
4081 }
4082 
4083 void ecvDisplayTools::RemoveAllWidgets(bool update /* = true*/) {
4085  context.removeEntityType = ENTITY_TYPE::ECV_ALL;
4087 
4088  if (update) {
4089  UpdateScreen();
4090  }
4091 }
4092 
4093 void ecvDisplayTools::Remove3DLabel(const QString& view_id) {
4095  context.removeViewID = view_id;
4096  context.removeEntityType = ENTITY_TYPE::ECV_TEXT2D;
4098  UpdateScreen();
4099 }
4100 
4102  ccGLCameraParameters camera;
4103  GetGLCameraParameters(camera);
4104 
4105  y = s_tools.instance->m_glViewport.height() - 1 - y;
4106 
4107  double glDepth = GetGLDepth(x, y);
4108  if (glDepth == 1.0) {
4109  return false;
4110  }
4111  CCVector3d P2D(x, y, glDepth);
4112  return camera.unproject(P2D, P3D);
4113 }
4114 
4116  if (!s_tools.instance->m_viewportParams.objectCenteredView ||
4117  (s_tools.instance->m_pivotVisibility == PIVOT_HIDE) ||
4118  (s_tools.instance->m_pivotVisibility == PIVOT_SHOW_ON_MOVE &&
4119  !s_tools.instance->m_pivotSymbolShown)) {
4120  return;
4121  }
4122 
4123  // place origin on pivot point
4124  CCVector3d tranlateTartget =
4125  CCVector3d(s_tools.instance->m_viewportParams.getPivotPoint().x,
4126  s_tools.instance->m_viewportParams.getPivotPoint().y,
4127  s_tools.instance->m_viewportParams.getPivotPoint().z);
4128 
4129  // compute actual symbol radius
4130  double symbolRadius = CC_DISPLAYED_PIVOT_RADIUS_PERCENT *
4131  std::min(s_tools.instance->m_glViewport.width(),
4132  s_tools.instance->m_glViewport.height()) /
4133  2.0;
4134 
4135  // draw a small sphere
4136  {
4137  ccSphere sphere(static_cast<PointCoordinateType>(10.0 / symbolRadius));
4138  sphere.setColor(ecvColor::yellow);
4139  sphere.showColors(true);
4140  sphere.setVisible(true);
4141  sphere.setEnabled(true);
4142  // force lighting for proper sphere display
4143  CC_DRAW_CONTEXT CONTEXT;
4144  GetContext(CONTEXT);
4145  CONTEXT.drawingFlags =
4147  sphere.draw(CONTEXT);
4148  }
4149 }
4150 
4151 void ecvDisplayTools::SetCurrentScreen(QWidget* widget) {
4152  s_tools.instance->m_currentScreen = widget;
4153  widget->update();
4154 }
constexpr float MIN_POINT_SIZE_F
Definition: CVConst.h:78
static constexpr float CC_GL_MIN_ZOOM_RATIO
Definition: CVConst.h:85
static constexpr float CC_GL_MAX_ZOOM_RATIO
Definition: CVConst.h:84
constexpr float MIN_LINE_WIDTH_F
Definition: CVConst.h:80
constexpr float MAX_LINE_WIDTH_F
Definition: CVConst.h:81
CC_VIEW_ORIENTATION
View orientation.
Definition: CVConst.h:102
@ CC_ISO_VIEW_1
Definition: CVConst.h:109
@ CC_ISO_VIEW_2
Definition: CVConst.h:110
@ CC_FRONT_VIEW
Definition: CVConst.h:105
@ CC_TOP_VIEW
Definition: CVConst.h:103
@ CC_RIGHT_VIEW
Definition: CVConst.h:108
@ CC_BOTTOM_VIEW
Definition: CVConst.h:104
@ CC_BACK_VIEW
Definition: CVConst.h:106
@ CC_LEFT_VIEW
Definition: CVConst.h:107
constexpr double ZERO_TOLERANCE_D
Definition: CVConst.h:49
constexpr float MAX_POINT_SIZE_F
Definition: CVConst.h:79
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
Vector3Tpl< PointCoordinateType > CCVector3
Default 3D Vector.
Definition: CVGeom.h:798
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
Definition: CVTypes.h:97
std::string filename
std::shared_ptr< core::Tensor > image
int width
int size
int height
int offset
char type
math::float4 color
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
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Type y
Definition: CVGeom.h:137
Type u[3]
Definition: CVGeom.h:139
Type * data()
Definition: CVGeom.h:145
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:36
Type y
Definition: CVGeom.h:36
void normalize()
Sets vector norm to unity.
Definition: CVGeom.h:428
double normd() const
Returns vector norm (forces double precision output)
Definition: CVGeom.h:426
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
2D label (typically attached to points)
Definition: ecv2DLabel.h:22
bool addPickedPoint(ccGenericPointCloud *cloud, unsigned pointIndex, bool entityCenter=false)
Adds a point to this label.
Definition: ecv2DLabel.cpp:400
const PickedPoint & getPickedPoint(unsigned index) const
Returns a given point.
Definition: ecv2DLabel.h:194
bool isPointLegendDisplayed() const
Returns whether the point(s) legend is displayed.
Definition: ecv2DLabel.h:111
unsigned size() const
Returns current size.
Definition: ecv2DLabel.h:74
void setPosition(float x, float y)
Sets relative position.
Definition: ecv2DLabel.cpp:225
bool pointPicking(const CCVector2d &clickPos, const ccGLCameraParameters &camera, int &nearestPointIndex, double &nearestSquareDist) const
Point (marker) picking.
void update2DLabelView(CC_DRAW_CONTEXT &context, bool updateScreen=true)
Definition: ecv2DLabel.cpp:329
bool isDisplayedIn2D() const
Returns whether the label is displayed in 2D.
Definition: ecv2DLabel.h:117
2D viewport label
Bounding box structure.
Definition: ecvBBox.h:25
virtual ccBBox & Scale(const double s, const Eigen::Vector3d &center) override
Apply scaling to the geometry coordinates. Given a scaling factor , and center , a given point is tr...
Definition: ecvBBox.cpp:41
Camera (projective) sensor.
const cloudViewer::geometry::LineSet & getNearPlane() const
Clipping box.
Definition: ecvClipBox.h:22
void setClickedPoint(int x, int y, int screenWidth, int screenHeight, const ccGLMatrixd &viewMatrix)
Sets last clicked point (on screen)
Definition: ecvClipBox.cpp:492
void setActiveComponent(int id)
Sets currently active component.
Definition: ecvClipBox.cpp:383
virtual bool isVisible() const
Returns whether entity is visible or not.
virtual void setVisible(bool state)
Sets entity visibility.
virtual bool isSelected() const
Returns whether entity is selected or not.
virtual void showColors(bool state)
Sets colors visibility.
Vector3Tpl< T > getTranslationAsVec3D() const
Returns a copy of the translation as a CCVector3.
void applyRotation(Vector3Tpl< float > &vec) const
Applies rotation only to a 3D vector (in place) - float version.
T * data()
Returns a pointer to internal data.
void clearTranslation()
Clears translation.
static ccGLMatrixTpl< double > FromViewDirAndUpDir(const Vector3Tpl< double > &forward, const Vector3Tpl< double > &up)
Generates a 'viewing' matrix from a looking vector and a 'up' direction.
void invert()
Inverts transformation.
void setRotation(const float Rt[9])
Sets Rotation from a float array.
Vector3Tpl< T > getColumnAsVec3D(unsigned index) const
Returns a copy of a given column as a CCVector3.
static Eigen::Matrix< double, 3, 3 > ToEigenMatrix3(const ccGLMatrixTpl< float > &mat)
Double version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:56
Generic mesh interface.
virtual bool isShownAsWire() const
Returns whether the mesh is displayed as wired or with plain facets.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
virtual bool trianglePicking(const CCVector2d &clickPos, const ccGLCameraParameters &camera, int &nearestTriIndex, double &nearestSquareDist, CCVector3d &nearestPoint, CCVector3d *barycentricCoords=nullptr) const
Brute force triangle picking.
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
bool pointPicking(const CCVector2d &clickPos, const ccGLCameraParameters &camera, int &nearestPointIndex, double &nearestSquareDist, double pickWidth=2.0, double pickHeight=2.0, bool autoComputeOctree=false)
Point picking (brute force or octree-driven)
virtual void setColor(const ecvColor::Rgb &col)
Sets primitive color (shortcut)
static ccPolyline * ToPolyline(ccHObject *obj)
Converts current object to ccPolyline (if possible)
static cc2DViewportLabel * To2DViewportLabel(ccHObject *obj)
Converts current object to cc2DViewportLabel (if possible)
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
static cc2DLabel * To2DLabel(ccHObject *obj)
Converts current object to cc2DLabel (if possible)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
void draw(CC_DRAW_CONTEXT &context) override
Draws entity and its children.
ENTITY_TYPE getEntityType() const
QString getViewId() const
Definition: ecvHObject.h:225
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
void setRedrawFlagRecursive(bool redraw=false)
Definition: ecvHObject.cpp:772
void updateNameIn3DRecursive()
@ DP_PARENT_OF_OTHER
Definition: ecvHObject.h:266
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Definition: ecvHObject.cpp:534
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
Definition: ecvHObject.h:337
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Definition: ecvHObject.h:325
CV_CLASS_ENUM getClassID() const override
Returns class ID.
Definition: ecvHObject.h:232
Interactor interface (entity that can be dragged or clicked in a 3D view)
Definition: ecvInteractor.h:20
virtual unsigned getUniqueID() const
Returns object unique ID.
Definition: ecvObject.h:86
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
virtual bool isEnabled() const
Returns whether the object is enabled or not.
Definition: ecvObject.h:97
bool isKindOf(CV_CLASS_ENUM type) const
Definition: ecvObject.h:128
Colored polyline.
Definition: ecvPolyline.h:24
bool is2DMode() const
Returns whether the polyline is considered as 2D or 3D.
Definition: ecvPolyline.h:63
static void DrawColorRamp(const CC_DRAW_CONTEXT &context)
Sphere (primitive)
Definition: ecvSphere.h:16
A sub-mesh.
Definition: ecvSubMesh.h:19
ccMesh * getAssociatedMesh()
Returns the associated mesh.
Definition: ecvSubMesh.h:162
double getDiagNormd() const
Returns diagonal length (double precision)
Definition: BoundingBox.h:175
Vector3Tpl< T > getCenter() const
Returns center.
Definition: BoundingBox.h:164
T getDiagNorm() const
Returns diagonal length.
Definition: BoundingBox.h:172
bool isValid() const
Returns whether bounding box is valid or not.
Definition: BoundingBox.h:203
virtual unsigned size() const =0
Returns the number of points.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
virtual VerticesIndexes * getTriangleVertIndexes(unsigned triangleIndex)=0
Returns the indexes of the vertices of a given triangle.
virtual bool IsEmpty() const override
Definition: LineSet.h:61
RGB color structure.
Definition: ecvColorTypes.h:49
static void ProcessPickingResult(const PickingParameters &params, ccHObject *pickedEntity, int pickedItemIndex, const CCVector3 *nearestPoint=nullptr, const std::unordered_set< int > *selectedIDs=nullptr)
Processes the picking process result and sends the corresponding signal.
static ecvDisplayTools * TheInstance()
static void RemoveEntities(const ccHObject *obj)
static void SetAutoPickPivotAtCenter(bool state)
static int GetDevicePixelRatio()
static void RemoveWidgets(const WIDGETS_PARAMETER &param, bool update=false)
static void GetCameraUp(double *up, int viewport=0)
static void SetDisplayParameters(const ecvGui::ParamStruct &params)
Sets current parameters for this display.
static void GetViewerPos(int *viewPos, int viewport=0)
static bool ExclusiveFullScreen()
Returns whether the window is in exclusive full screen mode or not.
static void Init(ecvDisplayTools *displayTools, QMainWindow *win, bool stereoMode=false)
static int GetOptimizedFontSize(int baseFontSize=12)
float m_bubbleViewFov_deg
Bubble-view mode f.o.v. (degrees)
static void SetLineWithRecursive(PointCoordinateType with)
static void Update()
static double GetParallelScale(int viewport=0)
static void StartCPUBasedPointPicking(const PickingParameters &params)
Starts OpenGL picking process.
void onItemPickedFast(ccHObject *pickedEntity, int pickedItemIndex, int x, int y)
Reacts to the itemPickedFast signal.
static INTERACTION_FLAGS TRANSFORM_CAMERA()
static double GetGLDepth(int x, int y)
static void SetRemoveViewIDs(std::vector< removeInfo > &removeinfos)
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 UpdateProjectionMatrix()
static void SetPointSize(float size, bool silent=false, int viewport=0)
static void SetMainWindow(QMainWindow *win)
static void SetFocusToScreen()
Draws the main 3D layer.
static void SetPivotPoint(const CCVector3d &P, bool autoUpdateCameraPos=false, bool verbose=false)
Sets pivot point.
static void SetPivotVisibility(PivotVisibility vis)
Sets pivot visibility.
static CCVector3d GetRealCameraCenter()
static void ShowOrientationMarker()
double m_bbHalfDiag
Half size of the displayed objects bounding-box.
void cancelScheduledRedraw()
Cancels any scheduled redraw.
static void SetParallelScale(double scale, int viewport=0)
static QFont GetTextDisplayFont()
void onWheelEvent(float wheelDelta_deg)
static void SetRemoveAllFlag(bool state)
INTERACTION_FLAGS m_interactionFlags
Current intercation flags.
static void GetGLCameraParameters(ccGLCameraParameters &params)
Returns the current OpenGL camera parameters.
static float ComputePerspectiveZoom()
static void InvalidateViewport()
PICKING_MODE
Picking mode.
@ POINT_OR_TRIANGLE_OR_LABEL_PICKING
static void DisplayOverlayEntities(bool state)
static void SetViewportParameters(const ecvViewportParameters &params)
static int GetLabelFontPointSize()
Returns current font size for labels.
static bool ViewerPerspectiveEnabled()
Shortcut: returns whether viewer-based perspective mode is enabled.
MessageType
Message type.
static void RemoveBB(CC_DRAW_CONTEXT context)
static void FilterByEntityType(ccHObject::Container &labels, CV_CLASS_ENUM type)
static void StartPicking(PickingParameters &params)
Starts picking process.
std::list< ccInteractor * > m_activeItems
Currently active items.
static void DrawClickableItems(int xStart, int &yStart)
static void SetBaseViewMat(ccGLMatrixd &mat)
static bool USE_2D
static bool HideShowEntities(const ccHObject *obj, bool visible)
static int Height()
static void SetGLViewport(int x, int y, int w, int h)
Sets the OpenGL viewport (shortut)
static ccGLMatrixd ComputeProjectionMatrix(bool withGLfeatures, ProjectionMetrics *metrics=nullptr, double *eyeOffset=nullptr)
Computes the projection matrix.
static double GetCameraFovy(int viewport=0)
static ccHObject * GetSceneDB()
HotZone * m_hotZone
Hot zone.
static void DrawPivot()
static void SetSceneDB(ccHObject *root)
static void drawCross()
static void SetPixelSize(float pixelSize)
Sets pixel size (i.e. zoom base)
static void SetZoom(float value)
Sets current zoom.
static void ClearBubbleView()
static void SetPickingMode(PICKING_MODE mode=DEFAULT_PICKING)
QTimer m_scheduleTimer
Scheduler timer.
static void UpdateZoom(float zoomFactor)
Updates current zoom.
static const ecvGui::ParamStruct & GetDisplayParameters()
Returns current parameters for this display (const version)
static ccGLMatrixd & GetProjectionMatrix()
static void UpdateConstellationCenterAndZoom(const ccBBox *aBox=nullptr, bool redraw=true)
Center and zoom on a given bounding box.
static void GetCameraFocal(double *focal, int viewport=0)
ccHObject * m_winDBRoot
Window own DB.
static void DrawForeground(CC_DRAW_CONTEXT &CONTEXT)
MessagePosition
Default message positions on screen.
static bool GetClick3DPos(int x, int y, CCVector3d &P3D)
Returns the approximate 3D position of the clicked pixel.
static CCVector3d GetCurrentViewDir()
Returns current viewing direction.
static QString PickObject(double x=-1, double y=-1)
static CCVector3d GetCurrentUpDir()
Returns current up direction.
static int GetFontPointSize()
Returns current font size.
static void SetCurrentScreen(QWidget *widget)
PivotVisibility
Pivot symbol visibility.
static void Pick2DLabel(int x, int y)
static QRect GetScreenRect()
static void SetAspectRatio(float ar)
Sets current camera aspect ratio (width/height)
static void SetCameraFovy(double fovy, int viewport=0)
static int Width()
double m_cameraToBBCenterDist
Distance between the camera and the displayed objects bounding-box.
static void RenderText(int x, int y, const QString &str, const QFont &font=QFont(), const ecvColor::Rgbub &color=ecvColor::defaultLabelBkgColor, const QString &id="")
static void Deprecate3DLayer()
static INTERACTION_FLAGS TRANSFORM_ENTITIES()
static void drawTrihedron()
static ENTITY_TYPE ConvertToEntityType(const CV_CLASS_ENUM &type)
static INTERACTION_FLAGS GetInteractionMode()
Returns the current interaction flags.
static void ChangeEntityProperties(PROPERTY_PARAM &propertyParam, bool autoUpdate=true)
static void SetPointSizeRecursive(int size)
static void SetFontPointSize(int pixelSize)
Sets current font size.
ecvViewportParameters m_viewportParams
Viewport parameters (zoom, etc.)
static void ResetCameraClippingRange(int viewport=0)
static void ToBeRefreshed()
void onPointPicking(const CCVector3 &p, int index, const std::string &id)
static bool ProcessClickableItems(int x, int y)
Processes the clickable items.
static ccHObject * GetPickedEntity(const PickingParameters &params)
static void Remove3DLabel(const QString &view_id)
static void SetRedrawRecursive(bool redraw=false)
static const int DefaultPickRadius
Default picking radius value.
static void LockRotationAxis(bool state, const CCVector3d &axis)
Lock the rotation axis.
void scheduleFullRedraw(unsigned maxDelay_ms)
Schedules a full redraw.
static void SetCameraClip(double znear, double zfar, int viewport=0)
static void SetZNearCoef(double coef)
Sets current camera 'zNear' coefficient.
static void RedrawDisplay(bool only2D=false, bool forceRedraw=true)
static void SetCameraPosition(const CCVector3d &pos, int viewport=0)
static void SetBubbleViewMode(bool state)
Sets bubble-view mode state.
static void AddToOwnDB(ccHObject *obj, bool noDependency=true)
Adds an entity to window own DB.
void checkScheduledRedraw()
Checks for scheduled redraw.
qint64 m_scheduledFullRedrawTime
Scheduled full redraw (no LOD)
static void GetCameraClip(double *clipPlanes, int viewport=0)
static void ShowPivotSymbol(bool state)
Shows or hide the pivot symbol.
ccPolyline * m_rectPickingPoly
Rectangular picking polyline.
static QWidget * GetCurrentScreen()
static void RefreshDisplay(bool only2D=false, bool forceRedraw=true)
std::list< MessageToDisplay > m_messagesToDisplay
List of messages to display.
static bool USE_VTK_PICK
static ccHObject * GetOwnDB()
Returns window own DB.
bool m_bubbleViewModeEnabled
Bubble-view mode state.
static void SetAutoUpateCameraPos(bool state)
static ccGLMatrixd ComputeModelViewMatrix()
Computes the model view matrix.
QElapsedTimer m_timer
Internal timer.
static void ResizeGL(int w, int h)
Sets current zoom.
void itemPickedFast(ccHObject *entity, int subEntityID, int x, int y)
Signal emitted when an item is picked (FAST_PICKING mode only)
static void DrawWidgets(const WIDGETS_PARAMETER &param, bool update=false)
CCVector3 m_last_picked_point
static INTERACTION_FLAGS PAN_ONLY()
static void GetCameraPos(double *pos, int viewport=0)
static void DisplayText(const QString &text, int x, int y, unsigned char align=ALIGN_DEFAULT, float bkgAlpha=0.0f, const unsigned char *rgbColor=nullptr, const QFont *font=nullptr, const QString &id="")
Displays a string at a given 2D position.
static void CheckIfRemove()
static void Redraw2DLabel()
static void UpdateScreenSize()
static void SetCenterOfRotation(double x, double y, double z)
static bool IsRectangularPickingAllowed()
Returns whether rectangular picking is allowed or not.
static void GetCenterOfRotation(double center[3])
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.
static void StartOpenGLPicking(const PickingParameters &params)
Performs the picking with OpenGL.
static ecvGenericVisualizer3D * GetVisualizer3D()
static void SetCameraPos(const CCVector3d &P)
Sets camera position.
static void SetScaleBarVisible(bool visible)
int m_pickRadius
Picking radius (pixels)
static PICKING_MODE GetPickingMode()
static void SetFov(float fov)
Sets current camera f.o.v. (field of view) in degrees.
static void Display3DLabel(const QString &str, const CCVector3 &pos3D, const ecvColor::Rgbub *color=nullptr, const QFont &font=QFont())
Displays a string at a given 3D position.
static void UpdateModelViewMatrix()
void fastPickingFinished()
Signal emitted when fast picking is finished (FAST_PICKING mode only)
static ccGLMatrixd GenerateViewMat(CC_VIEW_ORIENTATION orientation)
static void SetPerspectiveState(bool state, bool objectCenteredView)
Set perspective state/mode.
static void UpdateNamePoseRecursive()
static void MoveCamera(float dx, float dy, float dz)
Displaces camera.
static void UpdateScreen()
static ccGLMatrixd & GetModelViewMatrix()
static void UpdateDisplayParameters()
static QImage RenderToImage(int zoomFactor=1, bool renderOverlayItems=false, bool silent=false, int viewport=0)
virtual void zoomCamera(double zoomFactor, int viewport=0)
static void DrawBackground(CC_DRAW_CONTEXT &CONTEXT)
static QFont GetLabelDisplayFont()
static double GetPlatformAwareDPIScale()
static void SetBubbleViewFov(float fov_deg)
Set bubble-view f.o.v. (in degrees)
static bool ObjectPerspectiveEnabled()
Shortcut: returns whether object-based perspective mode is enabled.
static void GetViewMatrix(double *viewArray, int viewport=0)
static CCVector3d ToVtkCoordinates(int x, int y, int z=0)
QPoint m_lastMousePos
Last mouse position.
static void ReleaseInstance()
static void LockPickingMode(bool state)
Locks picking mode.
static float GetFov()
Returns the current f.o.v. (field of view) in degrees.
static void SetLineWidth(float width, bool silent=false, int viewport=0)
Sets line width.
virtual ~ecvDisplayTools() override
Destructor.
static void RemoveAllWidgets(bool update=true)
static QSize size()
static void GetContext(CC_DRAW_CONTEXT &CONTEXT)
Returns context information.
static QPointF ToCenteredGLCoordinates(int x, int y)
static void UpdateActiveItemsList(int x, int y, bool extendToSelectedLabels=false)
Updates currently active items list (m_activeItems)
static void SetView(CC_VIEW_ORIENTATION orientation, ccBBox *bbox)
static const ecvViewportParameters & GetViewportParameters()
static void DisplayTexture2DPosition(QImage image, const QString &id, int x, int y, int w, int h, unsigned char alpha=255)
static void InvalidateVisualization()
static double ComputeActualPixelSize()
static void RotateBaseViewMat(const ccGLMatrixd &rotMat)
Rotates the base view matrix.
PICKING_MODE m_pickingMode
static void GetVisibleObjectsBB(ccBBox &box)
Returns the visible objects bounding-box.
static void SetInteractionMode(INTERACTION_FLAGS flags)
static void ResetCamera()
static void ZoomCamera(double zoomFactor, int viewport=0)
static bool IsPickingModeLocked()
Returns whether picking mode is locked or not.
static void ZoomGlobal()
static void SetupProjectiveViewport(const ccGLMatrixd &cameraMatrix, float fov_deg=0.0f, float ar=1.0f, bool viewerBasedPerspective=true, bool bubbleViewMode=false)
static bool RenderToFile(QString filename, float zoomFactor=1.0f, bool dontScaleFeatures=false, bool renderOverlayItems=false)
Renders screen to a file.
static void SetRectangularPickingAllowed(bool state)
Sets whether rectangular picking is allowed or not.
static void Update2DLabel(bool immediateUpdate=false)
static ccGLMatrixd Ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
static void ToWorldPoint(const Vector3Tpl< iType > &input2D, Vector3Tpl< oType > &output3D)
static int FontSizeModifier(int fontSize, float zoomFactor)
static void SetInstance(ecvGenericDisplayTools *tool)
static ccGLMatrixd Frustum(double left, double right, double bottom, double top, double znear, double zfar)
void interactorPointPickedEvent(const CCVector3 &p, int index, const std::string &id)
static void Set(const ParamStruct &params)
Sets GUI parameters.
static const ParamStruct & Parameters()
Returns the stored values of each parameter.
static void UpdateParameters()
Standard parameters for GL displays/viewports.
bool perspectiveView
Perspective view state.
float fov_deg
Camera F.O.V. (field of view) in degrees.
float pixelSize
Current pixel size (in 'current unit'/pixel)
double zFar
Actual perspective 'zFar' value.
const CCVector3d & getCameraCenter() const
Returns the camera center.
void setPivotPoint(const CCVector3d &P, bool autoUpdateFocal=true)
Sets the pivot point (for object-centered view mode)
const CCVector3d & getPivotPoint() const
Returns the pivot point (for object-centered view mode)
ccGLMatrixd viewMat
Visualization matrix (rotation only)
void setCameraCenter(const CCVector3d &C, bool autoUpdateFocal=true)
Sets the camera center.
double zNear
Actual perspective 'zNear' value.
static const float CC_DISPLAYED_CENTER_CROSS_LENGTH
static const double CC_DISPLAYED_CUSTOM_LIGHT_LENGTH
static const QString DEBUG_LAYER_ID
static ecvSingleton< ecvDisplayTools > s_tools
static const char c_ps_stereoGlassType[]
static const char c_ps_customLight[]
static const float CC_TRIHEDRON_TEXT_MARGIN
static const float CC_DISPLAYED_TRIHEDRON_AXES_LENGTH
static const int CC_MAX_PICKING_CLICK_DURATION_MS
static const char c_ps_groupName[]
static const char c_ps_perspectiveView[]
static const char c_ps_pivotVisibility[]
static const char c_ps_objectMode[]
float RoundScale(float equivalentWidth)
static const double CC_DISPLAYED_PIVOT_RADIUS_PERCENT
static int s_GlWindowNumber
static const char c_ps_sunLight[]
@ CC_DRAW_2D
@ CC_DRAW_FOREGROUND
@ CC_FAST_ENTITY_PICKING
@ CC_LIGHT_ENABLED
@ CC_VIRTUAL_TRANS_ENABLED
@ CC_DRAW_3D
@ CC_ENTITY_PICKING
@ WIDGET_RECTANGLE_2D
@ WIDGET_CAPTION
@ WIDGET_IMAGE
@ WIDGET_TRIANGLE_2D
@ WIDGET_POINTS_2D
@ WIDGET_COORDINATE
@ WIDGET_LINE_3D
@ WIDGET_SPHERE
@ WIDGET_T2D
@ WIDGET_SCALAR_BAR
@ WIDGET_T3D
@ WIDGET_POLYLINE
@ WIDGET_POLYLINE_2D
@ WIDGET_BBOX
@ WIDGET_POLYGONMESH
@ WIDGET_CIRCLE_2D
@ WIDGET_LINE_2D
ENTITY_TYPE
@ ECV_LINES_2D
@ ECV_SENSOR
@ ECV_TEXT3D
@ ECV_POLYLINE_2D
@ ECV_KDTREE
@ ECV_CAPTION
@ ECV_IMAGE
@ ECV_LINES_3D
@ ECV_TEXT2D
@ ECV_TRIANGLE_2D
@ ECV_MESH
@ ECV_ALL
@ ECV_NONE
@ ECV_OCTREE
@ ECV_2DLABLE
@ ECV_HIERARCHY_OBJECT
@ ECV_SHAPE
@ ECV_CIRCLE_2D
@ ECV_SCALAR_BAR
@ ECV_RECTANGLE_2D
@ ECV_2DLABLE_VIEWPORT
@ ECV_MARK_POINT
@ ECV_POINT_CLOUD
const double * e
GraphType data
Definition: graph_cut.cc:138
ImGuiContext * context
Definition: Window.cpp:76
normal_z y
normal_z x
normal_z z
@ SENSOR
Definition: CVTypes.h:116
@ HIERARCHY_OBJECT
Definition: CVTypes.h:103
@ PRIMITIVE
Definition: CVTypes.h:119
@ MESH
Definition: CVTypes.h:105
@ GBL_SENSOR
Definition: CVTypes.h:117
@ CLIPPING_BOX
Definition: CVTypes.h:143
@ IMAGE
Definition: CVTypes.h:114
@ COORDINATESYSTEM
Definition: CVTypes.h:145
@ CONE
Definition: CVTypes.h:123
@ MESH_GROUP
Definition: CVTypes.h:107
@ POINT_CLOUD
Definition: CVTypes.h:104
@ DISH
Definition: CVTypes.h:129
@ LABEL_2D
Definition: CVTypes.h:140
@ POLY_LINE
Definition: CVTypes.h:112
@ POINT_KDTREE
Definition: CVTypes.h:111
@ FACET
Definition: CVTypes.h:109
@ SUB_MESH
Definition: CVTypes.h:106
@ LINESET
Definition: CVTypes.h:152
@ QUADRIC
Definition: CVTypes.h:131
@ POINT_OCTREE
Definition: CVTypes.h:110
@ TORUS
Definition: CVTypes.h:122
@ EXTRU
Definition: CVTypes.h:130
@ SPHERE
Definition: CVTypes.h:121
@ CAMERA_SENSOR
Definition: CVTypes.h:118
@ PLANE
Definition: CVTypes.h:120
@ DISC
Definition: CVTypes.h:146
@ VIEWPORT_2D_LABEL
Definition: CVTypes.h:142
@ CYLINDER
Definition: CVTypes.h:126
void Sleep(int milliseconds)
Definition: Helper.cpp:278
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Definition: MiniVec.h:75
float RadiansToDegrees(int radians)
Convert radians to degrees.
Definition: CVMath.h:71
bool GreaterThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:37
float DegreesToRadians(int degrees)
Convert degrees to radians.
Definition: CVMath.h:98
bool LessThanEpsilon(float x)
Test a floating point number against our epsilon (a very small number).
Definition: CVMath.h:23
RgbTpl< ColorCompType > Rgb
3 components, default type
constexpr Rgba odarkGrey(MAX/2, MAX/2, MAX/2, OPACITY)
constexpr Rgbaf night(0.00f, 0.00f, 0.00f, 1.00F)
constexpr Rgba ored(MAX, 0, 0, OPACITY)
Rgbaf FromRgba(const Rgba &color)
constexpr Rgbaf bright(1.00f, 1.00f, 1.00f, 1.00f)
constexpr Rgb yellow(MAX, MAX, 0)
constexpr Rgba ogreen(0, MAX, 0, OPACITY)
constexpr Rgbub defaultLabelBkgColor(MAX, MAX, MAX)
constexpr Rgbaf dark(0.34f, 0.34f, 0.34f, 1.00f)
ccHObject * entity
ENTITY_TYPE entityType
QString viewId
Display scalar field (prioritary on colors)
LineWidget lineWidget
ecvColor::Rgbaf color
WIDGETS_TYPE type
ccHObject * entity
CCVector3 getPointPosition() const
Returns the point position (3D)
Definition: ecv2DLabel.cpp:74
OpenGL camera parameters.
float fov_deg
F.O.V. (in degrees) - perspective mode only.
ccGLMatrixd projectionMat
Projection matrix (GL_PROJECTION)
ccGLMatrixd modelViewMat
Model view matrix (GL_MODELVIEW)
bool unproject(const CCVector3d &input2D, CCVector3d &output3D) const
Unprojects a 2D point (+ normalized 'z' coordinate) in 3D.
float pixelSize
Pixel size (i.e. zoom) - non perspective mode only.
bool perspective
Perspective mode.
bool project(const CCVector3d &input3D, CCVector3d &output2D, bool *inFrustum=nullptr) const
Projects a 3D point in 2D (+ normalized 'z' coordinate)
int viewport[4]
Viewport (GL_VIEWPORT)
Display context.
ecvColor::Rgbub pointsDefaultCol
Default point color.
ecvColor::Rgbub bbDefaultCol
Default bounding-box color.
float devicePixelRatio
Device pixel ratio (general 1, 2 on HD displays)
float labelMarkerSize
Label marker size (radius)
int drawingFlags
Drawing options (see below)
bool higherLODLevelsAvailable
Wheter higher levels are available or not.
unsigned labelOpacity
Label background opacity.
unsigned minLODPointCount
Minimum number of points for activating LOD display.
ecvColor::Rgbub labelDefaultBkgCol
Default label background color.
int glH
GL screen height.
ecvColor::Rgbub backgroundCol2
bool moreLODPointsAvailable
Wheter more points are available or not at the current level.
unsigned dispNumberPrecision
Numerical precision (for displaying text)
ecvColor::Rgbub labelDefaultMarkerCol
Default label marker color.
ecvColor::Rgbub backgroundCol
unsigned char currentLODLevel
Current level for LOD display.
float labelMarkerTextShift_pix
Shift for 3D label marker display (around the marker, in pixels)
ccMaterial::Shared defaultMat
Default material.
int glW
GL screen widthecvColor.
unsigned minLODTriangleCount
Minimum number of triangles for activating LOD display.
ccScalarField * sfColorScaleToDisplay
Currently displayed color scale (the corresponding scalar field in fact)
ecvColor::Rgbub textDefaultCol
Default text color.
bool useVBOs
Use VBOs for faster display.
bool decimateCloudOnMove
Whether to decimate big clouds when updating the 3D view.
bool drawRoundedPoints
Whether to draw rounded points (instead of sqaures)
Triangle described by the indexes of its 3 vertices.
Precomputed stuff for the 'hot zone'.
Temporary Message to display in the lower-left corner.
MessagePosition position
Message position on screen.
qint64 messageValidity_sec
Message end time (sec)
MessageType type
Message type.
Optional output metrics (from computeProjectionMatrix)
GUI parameters.
ComputeOctreeForPicking
Octree computation (for picking) behaviors.
ecvColor::Rgbaf meshSpecular
Default mesh specular color.
unsigned labelMarkerSize
Label marker size.
ecvColor::Rgbub backgroundCol
Background color.
unsigned displayedNumPrecision
Displayed numbers precision.
ComputeOctreeForPicking autoComputeOctree
Octree computation (for picking) behavior.
ecvColor::Rgbub labelMarkerCol
Labels marker color.
ecvColor::Rgbub textDefaultCol
Default text color.
bool drawRoundedPoints
Whether to draw rounded points (slower) or not.
unsigned minLoDCloudSize
Min cloud size for decimation.
ecvColor::Rgbub labelBackgroundCol
Labels background color.
ecvColor::Rgbub bbDefaultCol
Bounding-boxes color.
bool displayCross
Display cross in the middle of the screen.
void toPersistentSettings() const
Saves to persistent DB.
unsigned minLoDMeshSize
Min mesh size for decimation.
ecvColor::Rgbaf meshFrontDiff
Default mesh diffuse color (front)
bool drawBackgroundGradient
Use background gradient.
bool useVBOs
Whether to use VBOs for faster display.
unsigned labelOpacity
Labels background opcaity.
ecvColor::Rgbaf meshBackDiff
Default mesh diffuse color (back)
double zoomSpeed
Zoom speed (1.0 by default)
bool decimateCloudOnMove
Decimate clouds when moved.
ecvColor::Rgbub pointsDefaultCol
Default 3D points color.
Generic singleton encapsulation structure.
Definition: ecvSingleton.h:12
to be removed structure
ENTITY_TYPE removeType
Remove type.
QString removeId
Remove viewId.