GCC Code Coverage Report


Directory: ./
File: src/gui/pick-handler.cc
Date: 2025-04-14 11:18:00
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