GCC Code Coverage Report


Directory: ./
File: src/gui/pick-handler.cc
Date: 2024-08-14 11:04:57
Exec Total Coverage
Lines: 0 158 0.0%
Branches: 0 269 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
288