diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 5e1cfc5048cb1ac6cb0c890b4e70b65c12f87930..64b1b4e2c0239432e9bf21bb35406178f2fc6734 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -223,7 +223,8 @@ HEADERS += src/MG.h \ src/ui/map3D/PixhawkCheetahGeode.h \ src/comm/QGCMAVLink.h \ src/ui/map3D/Pixhawk3DWidget.h \ - src/ui/map3D/Q3DWidgetFactory.h + src/ui/map3D/Q3DWidgetFactory.h \ + src/ui/map3D/GCManipulator.h SOURCES += src/main.cc \ src/Core.cc \ src/uas/UASManager.cc \ @@ -297,7 +298,8 @@ SOURCES += src/main.cc \ src/ui/map3D/Q3DWidget.cc \ src/ui/map3D/PixhawkCheetahGeode.cc \ src/ui/map3D/Pixhawk3DWidget.cc \ - src/ui/map3D/Q3DWidgetFactory.cc + src/ui/map3D/Q3DWidgetFactory.cc \ + src/ui/map3D/GCManipulator.cc RESOURCES = mavground.qrc # Include RT-LAB Library diff --git a/src/ui/map3D/GCManipulator.cc b/src/ui/map3D/GCManipulator.cc new file mode 100644 index 0000000000000000000000000000000000000000..c4f2ac3e434a7e1f7e0267e442fef3c20158a530 --- /dev/null +++ b/src/ui/map3D/GCManipulator.cc @@ -0,0 +1,300 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2010 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Definition of the class GCManipulator. + * + * @author Lionel Heng + * + */ + +#include "GCManipulator.h" + +GCManipulator::GCManipulator() +{ + _moveSensitivity = 0.05; + _minZoomRange = 2.0; +} + +void +GCManipulator::setMinZoomRange(double minZoomRange) +{ + _minZoomRange = minZoomRange; +} + +bool +GCManipulator::handle(const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter& us) +{ + using namespace osgGA; + + switch (ea.getEventType()) + { + case GUIEventAdapter::PUSH: + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) + { + us.requestRedraw(); + } + us.requestContinuousUpdate(false); + _thrown = false; + return true; + } + + case GUIEventAdapter::RELEASE: + { + if (ea.getButtonMask() == 0) + { + if (isMouseMoving()) + { + if (calcMovement()) + { + us.requestRedraw(); + us.requestContinuousUpdate(true); + _thrown = true; + } + } + else + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) + { + us.requestRedraw(); + } + us.requestContinuousUpdate(false); + _thrown = false; + } + + } + else + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) + { + us.requestRedraw(); + } + us.requestContinuousUpdate(false); + _thrown = false; + } + return true; + } + + case GUIEventAdapter::DRAG: + { + addMouseEvent(ea); + if (calcMovement()) + { + us.requestRedraw(); + } + us.requestContinuousUpdate(false); + _thrown = false; + return true; + } + + case GUIEventAdapter::SCROLL: + { + // zoom model + float scale = 1.0f; + + if (ea.getScrollingMotion() == GUIEventAdapter::SCROLL_UP) + { + scale -= 0.1f; + } + else + { + scale += 0.1f; + } + if (_distance * scale > _minZoomRange) + { + + _distance *= scale; + + } + + return true; + } + + case GUIEventAdapter::KEYDOWN: + // pan model + switch (ea.getKey()) + { + case GUIEventAdapter::KEY_Space: + { + flushMouseEventStack(); + _thrown = false; + home(ea,us); + us.requestRedraw(); + us.requestContinuousUpdate(false); + return true; + } + case GUIEventAdapter::KEY_Left: + { + float scale = -_moveSensitivity * _distance; + + osg::Matrix rotation_matrix; + rotation_matrix.makeRotate(_rotation); + + osg::Vec3 dv(scale, 0.0f, 0.0f); + + _center += dv * rotation_matrix; + + return true; + } + case GUIEventAdapter::KEY_Right: + { + float scale = _moveSensitivity * _distance; + + osg::Matrix rotation_matrix; + rotation_matrix.makeRotate(_rotation); + + osg::Vec3 dv(scale, 0.0f, 0.0f); + + _center += dv * rotation_matrix; + + return true; + } + case GUIEventAdapter::KEY_Up: + { + float scale = _moveSensitivity * _distance; + + osg::Matrix rotation_matrix; + rotation_matrix.makeRotate(_rotation); + + osg::Vec3 dv(0.0f, scale, 0.0f); + + _center += dv * rotation_matrix; + + return true; + } + case GUIEventAdapter::KEY_Down: + { + float scale = -_moveSensitivity * _distance; + + osg::Matrix rotation_matrix; + rotation_matrix.makeRotate(_rotation); + + osg::Vec3 dv(0.0f, scale, 0.0f); + + _center += dv * rotation_matrix; + + return true; + } + return false; + } + + case GUIEventAdapter::FRAME: + if (_thrown) + { + if (calcMovement()) + { + us.requestRedraw(); + } + } + return false; + + default: + return false; + } +} + + +bool +GCManipulator::calcMovement() +{ + using namespace osgGA; + + // return if less then two events have been added. + if (_ga_t0.get() == NULL || _ga_t1.get() == NULL) + { + return false; + } + + float dx = _ga_t0->getXnormalized() - _ga_t1->getXnormalized(); + float dy = _ga_t0->getYnormalized() - _ga_t1->getYnormalized(); + + // return if there is no movement. + if (dx == 0.0f && dy == 0.0f) + { + return false; + } + + unsigned int buttonMask = _ga_t1->getButtonMask(); + if (buttonMask == GUIEventAdapter::LEFT_MOUSE_BUTTON) + { + // rotate camera + osg::Vec3 axis; + float angle; + + float px0 = _ga_t0->getXnormalized(); + float py0 = _ga_t0->getYnormalized(); + + float px1 = _ga_t1->getXnormalized(); + float py1 = _ga_t1->getYnormalized(); + + trackball(axis, angle, px1, py1, px0, py0); + + osg::Quat new_rotate; + new_rotate.makeRotate(angle, axis); + + _rotation = _rotation * new_rotate; + + return true; + + } + else if (buttonMask == GUIEventAdapter::MIDDLE_MOUSE_BUTTON || + buttonMask == (GUIEventAdapter::LEFT_MOUSE_BUTTON | + GUIEventAdapter::RIGHT_MOUSE_BUTTON)) + { + // pan model + float scale = -0.3f * _distance; + + osg::Matrix rotation_matrix; + rotation_matrix.makeRotate(_rotation); + + osg::Vec3 dv(dx * scale, dy * scale, 0.0f); + + _center += dv * rotation_matrix; + + return true; + + } + else if (buttonMask == GUIEventAdapter::RIGHT_MOUSE_BUTTON) + { + // zoom model + float scale = 1.0f + dy; + if (_distance * scale > _minZoomRange) + { + + _distance *= scale; + + } + return true; + } + + return false; +} diff --git a/src/ui/map3D/GCManipulator.h b/src/ui/map3D/GCManipulator.h new file mode 100644 index 0000000000000000000000000000000000000000..49259a34250d9a6caeff6316c5089255f23b0b18 --- /dev/null +++ b/src/ui/map3D/GCManipulator.h @@ -0,0 +1,58 @@ +/*===================================================================== + +QGroundControl Open Source Ground Control Station + +(c) 2009, 2010 QGROUNDCONTROL PROJECT + +This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + +======================================================================*/ + +/** + * @file + * @brief Definition of the class GCManipulator. + * + * @author Lionel Heng + * + */ + +#ifndef GCMANIPULATOR_H +#define GCMANIPULATOR_H + +#include + +class GCManipulator : public osgGA::TrackballManipulator +{ +public: + GCManipulator(); + + void setMinZoomRange(double minZoomRange); + + /** + * @brief Handle events. + * @return True if event is handled; false otherwise. + */ + virtual bool handle(const osgGA::GUIEventAdapter& ea, + osgGA::GUIActionAdapter& us); + +protected: + bool calcMovement(); + + double _moveSensitivity; + double _minZoomRange; +}; + +#endif // GCMANIPULATOR_H diff --git a/src/ui/map3D/Pixhawk3DWidget.cc b/src/ui/map3D/Pixhawk3DWidget.cc index 96a42d9e40d3f89dde3931358c230010ff296ac4..15788205a86b151df09445a34ce38946764edb7d 100644 --- a/src/ui/map3D/Pixhawk3DWidget.cc +++ b/src/ui/map3D/Pixhawk3DWidget.cc @@ -51,8 +51,8 @@ Pixhawk3DWidget::Pixhawk3DWidget(QWidget* parent) , displayWaypoints(true) , followCamera(true) { + setCameraParams(2.0f, 30.0f, 0.01f, 10000.0f); init(15.0f); - setCameraParams(0.5f, 30.0f, 0.01f, 10000.0f); // generate Pixhawk Cheetah model egocentricMap->addChild(PixhawkCheetahGeode::instance()); @@ -177,7 +177,7 @@ Pixhawk3DWidget::showTrail(int32_t state) { if (!displayTrail) { - trailVertices->clear(); + trail.clear(); } displayTrail = true; @@ -255,7 +255,7 @@ Pixhawk3DWidget::display(void) updateHUD(robotX, robotY, robotZ, robotRoll, robotPitch, robotYaw); updateTrail(robotX, robotY, robotZ); - updateTarget(robotX, robotY, robotZ); + updateTarget(); updateWaypoints(); // set node visibility @@ -280,38 +280,64 @@ osg::ref_ptr Pixhawk3DWidget::createGrid(void) { osg::ref_ptr geode(new osg::Geode()); - osg::ref_ptr geometry(new osg::Geometry()); - geode->addDrawable(geometry.get()); + osg::ref_ptr fineGeometry(new osg::Geometry()); + osg::ref_ptr coarseGeometry(new osg::Geometry()); + geode->addDrawable(fineGeometry); + geode->addDrawable(coarseGeometry); float radius = 10.0f; float resolution = 0.25f; - osg::ref_ptr coords(new osg::Vec3Array); + osg::ref_ptr fineCoords(new osg::Vec3Array); + osg::ref_ptr coarseCoords(new osg::Vec3Array); // draw a 20m x 20m grid with 0.25m resolution for (float i = -radius; i <= radius; i += resolution) { - coords->push_back(osg::Vec3(i, -radius, 0.0f)); - coords->push_back(osg::Vec3(i, radius, 0.0f)); - coords->push_back(osg::Vec3(-radius, i, 0.0f)); - coords->push_back(osg::Vec3(radius, i, 0.0f)); + if (fabsf(i - roundf(i)) < 0.01f) + { + coarseCoords->push_back(osg::Vec3(i, -radius, 0.0f)); + coarseCoords->push_back(osg::Vec3(i, radius, 0.0f)); + coarseCoords->push_back(osg::Vec3(-radius, i, 0.0f)); + coarseCoords->push_back(osg::Vec3(radius, i, 0.0f)); + } + else + { + fineCoords->push_back(osg::Vec3(i, -radius, 0.0f)); + fineCoords->push_back(osg::Vec3(i, radius, 0.0f)); + fineCoords->push_back(osg::Vec3(-radius, i, 0.0f)); + fineCoords->push_back(osg::Vec3(radius, i, 0.0f)); + } } - geometry->setVertexArray(coords); + fineGeometry->setVertexArray(fineCoords); + coarseGeometry->setVertexArray(coarseCoords); osg::ref_ptr color(new osg::Vec4Array); color->push_back(osg::Vec4(0.5f, 0.5f, 0.5f, 1.0f)); - geometry->setColorArray(color); - geometry->setColorBinding(osg::Geometry::BIND_OVERALL); - - geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, coords->size())); - - osg::ref_ptr stateset(new osg::StateSet); - osg::ref_ptr linewidth(new osg::LineWidth()); - linewidth->setWidth(0.25f); - stateset->setAttributeAndModes(linewidth, osg::StateAttribute::ON); - stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); - geometry->setStateSet(stateset); + fineGeometry->setColorArray(color); + coarseGeometry->setColorArray(color); + fineGeometry->setColorBinding(osg::Geometry::BIND_OVERALL); + coarseGeometry->setColorBinding(osg::Geometry::BIND_OVERALL); + + fineGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, + 0, fineCoords->size())); + coarseGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, + coarseCoords->size())); + + osg::ref_ptr fineStateset(new osg::StateSet); + osg::ref_ptr fineLinewidth(new osg::LineWidth()); + fineLinewidth->setWidth(0.25f); + fineStateset->setAttributeAndModes(fineLinewidth, osg::StateAttribute::ON); + fineStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + fineGeometry->setStateSet(fineStateset); + + osg::ref_ptr coarseStateset(new osg::StateSet); + osg::ref_ptr coarseLinewidth(new osg::LineWidth()); + coarseLinewidth->setWidth(2.0f); + coarseStateset->setAttributeAndModes(coarseLinewidth, osg::StateAttribute::ON); + coarseStateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + coarseGeometry->setStateSet(coarseStateset); return geode; } @@ -508,7 +534,7 @@ Pixhawk3DWidget::updateTrail(float robotX, float robotY, float robotZ) } void -Pixhawk3DWidget::updateTarget(float robotX, float robotY, float robotZ) +Pixhawk3DWidget::updateTarget(void) { static double radius = 0.2; static bool expand = true; diff --git a/src/ui/map3D/Pixhawk3DWidget.h b/src/ui/map3D/Pixhawk3DWidget.h index c1048f3fe63bdc501c9e5bf5272339168830d61b..3f94576a5a89071905256a2f61b9f8bffd888709 100644 --- a/src/ui/map3D/Pixhawk3DWidget.h +++ b/src/ui/map3D/Pixhawk3DWidget.h @@ -82,7 +82,7 @@ private: void updateHUD(float robotX, float robotY, float robotZ, float robotRoll, float robotPitch, float robotYaw); void updateTrail(float robotX, float robotY, float robotZ); - void updateTarget(float robotX, float robotY, float robotZ); + void updateTarget(void); void updateWaypoints(void); void markTarget(void); diff --git a/src/ui/map3D/Q3DWidget.cc b/src/ui/map3D/Q3DWidget.cc index 2bcbfcf02111eb9a4f131c7db1477577e14f66a8..56872bbc53f76a5114f9ad773e2ccfee470d5998 100644 --- a/src/ui/map3D/Q3DWidget.cc +++ b/src/ui/map3D/Q3DWidget.cc @@ -51,7 +51,7 @@ Q3DWidget::Q3DWidget(QWidget* parent) , hudProjectionMatrix(new osg::Projection) { // set initial camera parameters - cameraParams.minZoomRange = 0.5f; + cameraParams.minZoomRange = 2.0f; cameraParams.cameraFov = 30.0f; cameraParams.minClipRange = 1.0f; cameraParams.maxClipRange = 10000.0f; @@ -94,8 +94,10 @@ Q3DWidget::init(float fps) egocentricMap->addChild(createRobot()); // set up camera control - cameraManipulator = new osgGA::TrackballManipulator; + cameraManipulator = new GCManipulator; setCameraManipulator(cameraManipulator); + cameraManipulator->setMinZoomRange(cameraParams.minZoomRange); + cameraManipulator->setDistance(cameraParams.minZoomRange * 2.0); connect(&timer, SIGNAL(timeout()), this, SLOT(redraw())); timer.start(static_cast(floorf(1000.0f / fps))); @@ -282,6 +284,7 @@ Q3DWidget::keyPressEvent(QKeyEvent* event) { return; } + if (event->text().isEmpty()) { osgGW->getEventQueue()->keyPress(convertKey(event->key())); diff --git a/src/ui/map3D/Q3DWidget.h b/src/ui/map3D/Q3DWidget.h index c3f91c05480643bf26438e936dce79c07bb01801..6650e854804b6e9cb96d7d4063202a2331a53887 100644 --- a/src/ui/map3D/Q3DWidget.h +++ b/src/ui/map3D/Q3DWidget.h @@ -39,6 +39,8 @@ This file is part of the QGROUNDCONTROL project #include #include +#include "GCManipulator.h" + /** * @brief Definition of the class Q3DWidget. * The Q3DWidget widget uses the OpenSceneGraph framework to render @@ -243,7 +245,7 @@ protected: osg::ref_ptr osgGW; /**< A class which manages OSG graphics windows and events. */ - osg::ref_ptr cameraManipulator; /**< Camera manipulator. */ + osg::ref_ptr cameraManipulator; /**< Camera manipulator. */ QTimer timer; /**< Timer which draws graphics based on specified fps. */