GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/gui/pick-handler.cc Lines: 1 122 0.8 %
Date: 2020-05-14 11:23:33 Branches: 2 223 0.9 %

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 <QDebug>
20
#include <QApplication>
21
22
#include <osg/io_utils>
23
24
#include <osgUtil/IntersectionVisitor>
25
#include <osgUtil/LineSegmentIntersector>
26
#include <osgGA/TrackballManipulator>
27
#include <osgGA/KeySwitchMatrixManipulator>
28
29
#include <osgViewer/Viewer>
30
31
#include <iostream>
32
33
#include <gepetto/viewer/node.h>
34
#include <gepetto/gui/selection-event.hh>
35
#include <gepetto/gui/windows-manager.hh>
36
#include <gepetto/gui/osgwidget.hh>
37
#include <gepetto/gui/mainwindow.hh>
38
#include <gepetto/gui/bodytreewidget.hh>
39
#include <gepetto/gui/tree-item.hh>
40
#include <gepetto/gui/selection-handler.hh>
41
42
namespace gepetto {
43
  namespace gui {
44
    PickHandler::PickHandler(OSGWidget *parent, WindowsManagerPtr_t wsm)
45
      : osgGA::GUIEventHandler ()
46
      , wsm_ (wsm)
47
      , parent_ (parent)
48
      , pushed_ (false)
49
      , lastX_ (0)
50
      , lastY_ (0)
51
      , intersector_ (new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, 0., 0.))
52
    {
53
      intersector_->setIntersectionLimit( osgUtil::Intersector::LIMIT_NEAREST );
54
    }
55
56
    PickHandler::~PickHandler()
57
    {
58
    }
59
60
    bool PickHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
61
    {
62
      switch (ea.getEventType()) {
63
        case osgGA::GUIEventAdapter::PUSH:
64
        case osgGA::GUIEventAdapter::RELEASE:
65
          if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) {
66
            if (pushed_
67
                && 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(), ea.getModKeyMask());
72
                return true;
73
              }
74
            }
75
            if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH) {
76
              lastX_ = ea.getX();
77
              lastY_ = ea.getY();
78
              pushed_ = true;
79
            }
80
          }
81
          return false;
82
          break;
83
        case osgGA::GUIEventAdapter::KEYUP:
84
          switch (ea.getKey ()) {
85
            case 'z':
86
                setCameraToSelected (aa, false);
87
                return true;
88
            case 'Z':
89
                setCameraToSelected (aa, true);
90
              return true;
91
            case 'f':
92
                centerViewToMouse (aa, ea.getX(), ea.getY());
93
              return true;
94
            default:
95
              break;
96
          }
97
          break;
98
        default:
99
          break;
100
      }
101
      return false;
102
    }
103
104
    void PickHandler::getUsage (osg::ApplicationUsage& usage) const
105
    {
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::computeIntersection(osgGA::GUIActionAdapter &aa,
113
        const float &x, const float &y)
114
    {
115
      intersector_->reset();
116
      intersector_->setStart (osg::Vec3d(x,y,0.));
117
      intersector_->setEnd   (osg::Vec3d(x,y,1.));
118
119
      osgViewer::View* viewer = dynamic_cast<osgViewer::View*>( &aa );
120
      if( viewer )
121
      {
122
          // There is no need to lock the windows manager mutex
123
          // as this is treated in the event loop of OSG, and not Qt.
124
          // On the contrary, locking here creates a deadlock as the lock is
125
          // already acquired by OSGWidget::paintEvent.
126
          // wsm_->lock().lock();
127
          //osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector =
128
              //new osgUtil::LineSegmentIntersector(osgUtil::Intersector::WINDOW, x, y);
129
          //intersector->setIntersectionLimit( osgUtil::Intersector::LIMIT_NEAREST );
130
131
          osgUtil::IntersectionVisitor iv( intersector_ );
132
          iv.setTraversalMask(viewer::IntersectionBit);
133
          //iv.setTraversalMask(viewer::IntersectionBit | viewer::EditionBit);
134
135
          osg::Camera* camera = viewer->getCamera();
136
          camera->accept( iv );
137
      }
138
    }
139
140
    void PickHandler::selectionNodeUnderCursor (osgGA::GUIActionAdapter &aa,
141
        const float &x, const float &y, int modKeyMask)
142
    {
143
      computeIntersection (aa, x, y);
144
      BodyTreeWidget* bt = MainWindow::instance()->bodyTree();
145
146
      if( !intersector_->containsIntersections() ) {
147
        bt->emitBodySelected(new SelectionEvent(SelectionEvent::FromOsgWindow,
148
              QApplication::keyboardModifiers()));
149
        return;
150
      }
151
152
      // Only one intersection. Otherwise, one has to loop on elements of
153
      // intersector->getIntersections();
154
      const osgUtil::LineSegmentIntersector::Intersection&
155
        intersection = intersector_->getFirstIntersection();
156
      for (int i = (int) intersection.nodePath.size()-1; i >= 0 ; --i) {
157
        //if (intersection.nodePath[i]->getNodeMask() == viewer::EditionBit) {
158
          // TODO start editing node configuration.
159
          // qDebug() << "edition bit";
160
          //break;
161
        //}
162
        if (!(intersection.nodePath[i]->getNodeMask() & viewer::NodeBit)) continue;
163
        NodePtr_t n = wsm_->getNode(intersection.nodePath[i]->getName ());
164
        if (n) {
165
          SelectionEvent *event = new SelectionEvent(SelectionEvent::FromOsgWindow,
166
              n,
167
              mapper_.getQtModKey(modKeyMask));
168
          event->setupIntersection(intersection);
169
          bt->emitBodySelected(event);
170
          return;
171
        }
172
      }
173
    }
174
175
    void PickHandler::centerViewToMouse (osgGA::GUIActionAdapter &aa,
176
        const float &x, const float &y)
177
    {
178
      osgViewer::View* viewer = dynamic_cast<osgViewer::View*>( &aa );
179
      if(!viewer) return;
180
181
      computeIntersection (aa, x, y);
182
      if( !intersector_->containsIntersections() ) return;
183
184
      // Only one intersection. Otherwise, one has to loop on elements of
185
      // intersector->getIntersections();
186
      const osgUtil::LineSegmentIntersector::Intersection&
187
        intersection = intersector_->getFirstIntersection();
188
189
      osg::Vec3f P (intersection.getWorldIntersectPoint());
190
191
      osgGA::TrackballManipulator* tbm = dynamic_cast<osgGA::TrackballManipulator*>(viewer->getCameraManipulator());
192
      if (!tbm) {
193
        osgGA::KeySwitchMatrixManipulator* ksm = dynamic_cast<osgGA::KeySwitchMatrixManipulator*>(viewer->getCameraManipulator());
194
        if (ksm) {
195
          tbm = dynamic_cast<osgGA::TrackballManipulator*>(ksm->getCurrentMatrixManipulator());
196
        }
197
      }
198
      if (tbm) {
199
        tbm->setCenter(P);
200
      } else {
201
        osg::Vec3f eye, center, up;
202
        viewer->getCameraManipulator()->getInverseMatrix ()
203
          .getLookAt (eye, center, up);
204
205
        osg::Vec3f u (center-eye); u.normalize();
206
        osg::Vec3f v (up^u);
207
        osg::Vec3f t (v * (v * (P-eye)));
208
        eye    += t;
209
        center += t;
210
        viewer->getCameraManipulator()->setByInverseMatrix (
211
            osg::Matrix::lookAt (eye, center, up)
212
            );
213
      }
214
    }
215
216
    void PickHandler::setCameraToSelected (osgGA::GUIActionAdapter &aa,
217
        bool zoom)
218
    {
219
      MainWindow* main = MainWindow::instance();
220
      NodePtr_t last = main->osg()->getNode(
221
            main->selectionHandler()->mode()->currentBody().toStdString()
222
            );
223
      if (!last) return;
224
      osgViewer::View* viewer = dynamic_cast<osgViewer::View*>( &aa );
225
      if(!viewer) return;
226
227
      const osg::BoundingSphere& bs = last->asGroup()->getBound ();
228
      osg::Vec3f eye, center, up;
229
      viewer->getCameraManipulator()->getInverseMatrix ()
230
        .getLookAt (eye, center, up);
231
232
      osgGA::TrackballManipulator* tbm = dynamic_cast<osgGA::TrackballManipulator*>(viewer->getCameraManipulator());
233
      if (!tbm) {
234
        osgGA::KeySwitchMatrixManipulator* ksm = dynamic_cast<osgGA::KeySwitchMatrixManipulator*>(viewer->getCameraManipulator());
235
        if (ksm) {
236
          tbm = dynamic_cast<osgGA::TrackballManipulator*>(ksm->getCurrentMatrixManipulator());
237
        }
238
      }
239
      if (tbm) {
240
        tbm->setCenter(bs.center());
241
        if (zoom) tbm->setDistance(3 * bs.radius());
242
      } else {
243
        if (zoom) {
244
          osg::Vec3f tmp = center - eye;
245
          tmp.normalize();
246
          eye = bs.center() - tmp * 3 * bs.radius();
247
        } else {
248
          eye += bs.center() - center;
249
        }
250
        viewer->getCameraManipulator()->setByInverseMatrix (
251
            osg::Matrixd::lookAt (eye, bs.center(), up)
252
            );
253
      }
254
    }
255
  }
256

3
}