GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gui/pick-handler.cc Lines: 0 151 0.0 %
Date: 2024-04-14 11:13:22 Branches: 0 265 0.0 %

Line Branch Exec Source
1
// Copyright (c) 2015-2018, LAAS-CNRS
2
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3
//
4
// This file is part of gepetto-viewer.
5
// gepetto-viewer is free software: you can redistribute it
6
// and/or modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation, either version
8
// 3 of the License, or (at your option) any later version.
9
//
10
// gepetto-viewer is distributed in the hope that it will be
11
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
// General Lesser Public License for more details. You should have
14
// received a copy of the GNU Lesser General Public License along with
15
// gepetto-viewer. If not, see <http://www.gnu.org/licenses/>.
16
17
#include "gepetto/gui/pick-handler.hh"
18
19
#include <gepetto/viewer/node.h>
20
21
#include <QApplication>
22
#include <QDebug>
23
#include <QStatusBar>
24
#include <gepetto/gui/bodytreewidget.hh>
25
#include <gepetto/gui/mainwindow.hh>
26
#include <gepetto/gui/osgwidget.hh>
27
#include <gepetto/gui/selection-event.hh>
28
#include <gepetto/gui/selection-handler.hh>
29
#include <gepetto/gui/tree-item.hh>
30
#include <gepetto/gui/windows-manager.hh>
31
#include <iostream>
32
#include <osg/io_utils>
33
#include <osgGA/KeySwitchMatrixManipulator>
34
#include <osgGA/TrackballManipulator>
35
#include <osgUtil/IntersectionVisitor>
36
#include <osgUtil/LineSegmentIntersector>
37
#include <osgViewer/Viewer>
38
39
#include "point-intersector.hh"
40
41
namespace gepetto {
42
namespace gui {
43
PickHandler::PickHandler(OSGWidget* parent, WindowsManagerPtr_t wsm)
44
    : osgGA::GUIEventHandler(),
45
      wsm_(wsm),
46
      parent_(parent),
47
      pushed_(false),
48
      lastX_(0),
49
      lastY_(0),
50
      lineIntersector_(new osgUtil::LineSegmentIntersector(
51
          osgUtil::Intersector::WINDOW, 0., 0.)),
52
      pointIntersector_(
53
          new PointIntersector(osgUtil::Intersector::WINDOW, 0., 0.)) {
54
  lineIntersector_->setIntersectionLimit(osgUtil::Intersector::LIMIT_NEAREST);
55
  pointIntersector_->setPickBias(0.01f);
56
  pointIntersector_->setIntersectionLimit(osgUtil::Intersector::LIMIT_NEAREST);
57
}
58
59
PickHandler::~PickHandler() {}
60
61
bool PickHandler::handle(const osgGA::GUIEventAdapter& ea,
62
                         osgGA::GUIActionAdapter& aa) {
63
  switch (ea.getEventType()) {
64
    case osgGA::GUIEventAdapter::PUSH:
65
    case osgGA::GUIEventAdapter::RELEASE:
66
      if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) {
67
        if (pushed_ && ea.getEventType() == osgGA::GUIEventAdapter::RELEASE) {
68
          pushed_ = false;
69
          if ((int)floor(lastX_ - ea.getX() + 0.5) == 0 &&
70
              (int)floor(lastY_ - ea.getY() + 0.5) == 0) {
71
            selectionNodeUnderCursor(aa, ea.getX(), ea.getY(),
72
                                     ea.getModKeyMask());
73
            return true;
74
          }
75
        }
76
        if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH) {
77
          lastX_ = ea.getX();
78
          lastY_ = ea.getY();
79
          pushed_ = true;
80
        }
81
      }
82
      return false;
83
      break;
84
    case osgGA::GUIEventAdapter::KEYUP:
85
      switch (ea.getKey()) {
86
        case 'z':
87
          setCameraToSelected(aa, false);
88
          return true;
89
        case 'Z':
90
          setCameraToSelected(aa, true);
91
          return true;
92
        case 'f':
93
          centerViewToMouse(aa, ea.getX(), ea.getY());
94
          return true;
95
        default:
96
          break;
97
      }
98
      break;
99
    default:
100
      break;
101
  }
102
  return false;
103
}
104
105
void PickHandler::getUsage(osg::ApplicationUsage& usage) const {
106
  usage.addKeyboardMouseBinding("Right click", "Select node");
107
  usage.addKeyboardMouseBinding('z', "Move camera on selected node");
108
  usage.addKeyboardMouseBinding('Z', "Move and zoom on selected node");
109
  usage.addKeyboardMouseBinding('f', "Center view to mouse");
110
}
111
112
void PickHandler::computeLineIntersection(osgGA::GUIActionAdapter& aa,
113
                                          const float& x, const float& y) {
114
  lineIntersector_->reset();
115
  lineIntersector_->setStart(osg::Vec3d(x, y, 0.));
116
  lineIntersector_->setEnd(osg::Vec3d(x, y, 1.));
117
118
  osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa);
119
  if (viewer) {
120
    // There is no need to lock the windows manager mutex
121
    // as this is treated in the event loop of OSG, and not Qt.
122
    // On the contrary, locking here creates a deadlock as the lock is
123
    // already acquired by OSGWidget::paintEvent.
124
    // wsm_->lock().lock();
125
    // osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
126
    // new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y);
127
    // intersector->setIntersectionLimit( osgUtil::Intersector::LIMIT_NEAREST );
128
129
    osgUtil::IntersectionVisitor iv(lineIntersector_);
130
    iv.setTraversalMask(viewer::IntersectionBit);
131
132
    osg::Camera* camera = viewer->getCamera();
133
    camera->accept(iv);
134
  }
135
}
136
137
PickHandler::LineSegmentIntersector PickHandler::computeLineOrPointIntersection(
138
    osgGA::GUIActionAdapter& aa, const float& x, const float& y) {
139
  osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa);
140
  if (!viewer) return LineSegmentIntersector();
141
  osg::Camera* camera = viewer->getCamera();
142
143
  lineIntersector_->reset();
144
  lineIntersector_->setStart(osg::Vec3d(x, y, 0.));
145
  lineIntersector_->setEnd(osg::Vec3d(x, y, 1.));
146
  {
147
    osgUtil::IntersectionVisitor iv(lineIntersector_);
148
    iv.setTraversalMask(viewer::IntersectionBit);
149
    camera->accept(iv);
150
  }
151
  if (lineIntersector_->containsIntersections()) return lineIntersector_;
152
153
  pointIntersector_->reset();
154
  pointIntersector_->setStart(osg::Vec3d(x, y, 0.));
155
  pointIntersector_->setEnd(osg::Vec3d(x, y, 1.));
156
  {
157
    osgUtil::IntersectionVisitor iv(pointIntersector_);
158
    iv.setTraversalMask(viewer::IntersectionBit);
159
    // iv.setTraversalMask(viewer::IntersectionBit | viewer::EditionBit);
160
    camera->accept(iv);
161
  }
162
  if (pointIntersector_->containsIntersections()) return pointIntersector_;
163
  return LineSegmentIntersector();
164
}
165
166
void PickHandler::selectionNodeUnderCursor(osgGA::GUIActionAdapter& aa,
167
                                           const float& x, const float& y,
168
                                           int modKeyMask) {
169
  LineSegmentIntersector li = computeLineOrPointIntersection(aa, x, y);
170
  BodyTreeWidget* bt = MainWindow::instance()->bodyTree();
171
172
  if (!li || !li->containsIntersections()) {
173
    bt->emitBodySelected(new SelectionEvent(SelectionEvent::FromOsgWindow,
174
                                            QApplication::keyboardModifiers()));
175
    return;
176
  }
177
178
  // Only one intersection. Otherwise, one has to loop on elements of
179
  // intersector->getIntersections();
180
  const osgUtil::LineSegmentIntersector::Intersection& intersection =
181
      li->getFirstIntersection();
182
  for (int i = (int)intersection.nodePath.size() - 1; i >= 0; --i) {
183
    if (!(intersection.nodePath[i]->getNodeMask() & viewer::NodeBit)) continue;
184
    NodePtr_t n = wsm_->getNode(intersection.nodePath[i]->getName());
185
    if (n) {
186
      SelectionEvent* event = new SelectionEvent(
187
          SelectionEvent::FromOsgWindow, n, mapper_.getQtModKey(modKeyMask));
188
      event->setupIntersection(intersection);
189
      bt->emitBodySelected(event);
190
191
      QStatusBar* statusBar = MainWindow::instance()->statusBar();
192
      statusBar->clearMessage();
193
      if (osg::dynamic_pointer_cast<PointIntersector>(li))
194
        statusBar->showMessage(QString::fromStdString(n->getID()) +
195
                               QString(" - Vectex index: ") +
196
                               QString::number(intersection.primitiveIndex));
197
      else
198
        statusBar->showMessage(QString::fromStdString(n->getID()));
199
      return;
200
    }
201
  }
202
}
203
204
void PickHandler::centerViewToMouse(osgGA::GUIActionAdapter& aa, const float& x,
205
                                    const float& y) {
206
  osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa);
207
  if (!viewer) return;
208
209
  computeLineIntersection(aa, x, y);
210
  if (!lineIntersector_->containsIntersections()) return;
211
212
  // Only one intersection. Otherwise, one has to loop on elements of
213
  // intersector->getIntersections();
214
  const osgUtil::LineSegmentIntersector::Intersection& intersection =
215
      lineIntersector_->getFirstIntersection();
216
217
  osg::Vec3f P(intersection.getWorldIntersectPoint());
218
219
  osgGA::TrackballManipulator* tbm = dynamic_cast<osgGA::TrackballManipulator*>(
220
      viewer->getCameraManipulator());
221
  if (!tbm) {
222
    osgGA::KeySwitchMatrixManipulator* ksm =
223
        dynamic_cast<osgGA::KeySwitchMatrixManipulator*>(
224
            viewer->getCameraManipulator());
225
    if (ksm) {
226
      tbm = dynamic_cast<osgGA::TrackballManipulator*>(
227
          ksm->getCurrentMatrixManipulator());
228
    }
229
  }
230
  if (tbm) {
231
    tbm->setCenter(P);
232
  } else {
233
    osg::Vec3f eye, center, up;
234
    viewer->getCameraManipulator()->getInverseMatrix().getLookAt(eye, center,
235
                                                                 up);
236
237
    osg::Vec3f u(center - eye);
238
    u.normalize();
239
    osg::Vec3f v(up ^ u);
240
    osg::Vec3f t(v * (v * (P - eye)));
241
    eye += t;
242
    center += t;
243
    viewer->getCameraManipulator()->setByInverseMatrix(
244
        osg::Matrix::lookAt(eye, center, up));
245
  }
246
}
247
248
void PickHandler::setCameraToSelected(osgGA::GUIActionAdapter& aa, bool zoom) {
249
  MainWindow* main = MainWindow::instance();
250
  NodePtr_t last = main->osg()->getNode(
251
      main->selectionHandler()->mode()->currentBody().toStdString());
252
  if (!last) return;
253
  osgViewer::View* viewer = dynamic_cast<osgViewer::View*>(&aa);
254
  if (!viewer) return;
255
256
  const osg::BoundingSphere& bs = last->asGroup()->getBound();
257
  osg::Vec3f eye, center, up;
258
  viewer->getCameraManipulator()->getInverseMatrix().getLookAt(eye, center, up);
259
260
  osgGA::TrackballManipulator* tbm = dynamic_cast<osgGA::TrackballManipulator*>(
261
      viewer->getCameraManipulator());
262
  if (!tbm) {
263
    osgGA::KeySwitchMatrixManipulator* ksm =
264
        dynamic_cast<osgGA::KeySwitchMatrixManipulator*>(
265
            viewer->getCameraManipulator());
266
    if (ksm) {
267
      tbm = dynamic_cast<osgGA::TrackballManipulator*>(
268
          ksm->getCurrentMatrixManipulator());
269
    }
270
  }
271
  if (tbm) {
272
    tbm->setCenter(bs.center());
273
    if (zoom) tbm->setDistance(3 * bs.radius());
274
  } else {
275
    if (zoom) {
276
      osg::Vec3f tmp = center - eye;
277
      tmp.normalize();
278
      eye = bs.center() - tmp * 3 * bs.radius();
279
    } else {
280
      eye += bs.center() - center;
281
    }
282
    viewer->getCameraManipulator()->setByInverseMatrix(
283
        osg::Matrixd::lookAt(eye, bs.center(), up));
284
  }
285
}
286
}  // namespace gui
287
}  // namespace gepetto