diff --git a/manifest.xml b/manifest.xml
index 048e861..4a960ac 100644
--- a/manifest.xml
+++ b/manifest.xml
@@ -24,6 +24,9 @@
resources/orientationView1.jpeg
+
+ resources/orientationView1.jpeg
+
resources/rangeView1.jpeg
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f5d28f2..914d5cb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -84,6 +84,8 @@ SET(COLLECTION_MOC_HDRS
sonar_widget/SonarPlot.h
sonar_widget/SonarWidget.h
sonar_widget/SonarWidgetPlugin.h
+ nav_ball/navball.h
+ nav_ball/navballplugin.h
)
SET(COLLECTION_HDRS
@@ -127,6 +129,8 @@ SET(COLLECTION_HDRS
sonar_widget/SonarPlot.h
sonar_widget/SonarWidget.h
sonar_widget/SonarWidgetPlugin.h
+ nav_ball/navball.h
+ nav_ball/navballplugin.h
)
FILE(GLOB COLLECTION_SOURCES
@@ -143,6 +147,7 @@ FILE(GLOB COLLECTION_SOURCES
image_view/*.cc
progress_indicator/*.cc
sonar_widget/*.cc
+ nav_ball/*.cc
*.cc)
if (USE_VTK)
@@ -176,6 +181,7 @@ rock_vizkit_widget(rock_widget_collection SHARED
HEADERS ${COLLECTION_HDRS}
MOC ${COLLECTION_MOC_HDRS}
DEPS_PKGCONFIG base-types base-lib frame_helper
+ QtOpenGL
DEPS_CMAKE QWT OpenGL ${VTK_DEPS}
LIBS ${QT_QTCORE_LIBRARY} ${VTK_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${QT_QTDESIGNER_LIBRARY} ${QTGSTREAMER_LIBRARIES} ${QTGSTREAMER_UI_LIBRARIES}
)
diff --git a/src/RockWidgetCollection.cc b/src/RockWidgetCollection.cc
index 83b8ee6..5c68bc6 100644
--- a/src/RockWidgetCollection.cc
+++ b/src/RockWidgetCollection.cc
@@ -17,6 +17,8 @@
#include "progress_indicator/ProgressIndicatorPlugin.h"
#include "sonar_widget/SonarWidgetPlugin.h"
+#include "nav_ball/navballplugin.h"
+
#ifdef USE_VTK
#include "vtk/sonar_display/SonarDisplayPlugin.h"
#include "vtk/vectorfield3D/vectorfield3DPlugin.h"
@@ -35,6 +37,7 @@ RockWidgetCollection::RockWidgetCollection(QObject *parent)
widgets.append(new MultiViewPlugin(this));
widgets.append(new MultiWidgetPlugin(this));
widgets.append(new OrientationPlugin(this));
+ widgets.append(new NavBallPlugin(this));
widgets.append(new Plot2dPlugin(this));
widgets.append(new ProgressIndicatorPlugin(this));
widgets.append(new RangeViewPlugin(this));
diff --git a/src/nav_ball/navball.cc b/src/nav_ball/navball.cc
new file mode 100644
index 0000000..001564e
--- /dev/null
+++ b/src/nav_ball/navball.cc
@@ -0,0 +1,124 @@
+#include "navball.h"
+#include
+#include
+
+#include
+
+
+NavBallView::NavBallView(QWidget* parent) : QGLWidget(parent), texture(0)
+{
+ setMinimumWidth(100);
+ setMinimumHeight(100);
+
+ Eigen::Matrix3f NWU;
+ NWU <<
+ +0,+1,+0,
+ +0,+0,+1,
+ +1,+0,+0;
+ nwu2gl = NWU.transpose();
+// std::cout << "NWU2GL: " << nwu2gl.coeffs().transpose() << '\n';
+}
+
+void NavBallView::initializeGL()
+{
+ makeSphere();
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_2D);
+
+ // optional: (but light position should be fixed relative to camera not to object)
+// glShadeModel(GL_SMOOTH);
+// glEnable(GL_LIGHTING);
+// glEnable(GL_LIGHT0);
+// glEnable(GL_MULTISAMPLE);
+// static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
+// glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
+}
+
+void NavBallView::resizeGL(int width, int height)
+{
+ int side = std::min(width, height);
+ glViewport((width - side) / 2, (height - side) / 2, side, side);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, +1, -1, +1, 4.0, 4.9);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+void NavBallView::paintGL()
+{
+ qglClearColor(Qt::black);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ Eigen::Quaternionf res = quat * nwu2gl;
+ res.x()*=-1.f; // invert tilt rotation
+ Eigen::Transform trafo(res);
+ trafo.translation() = Eigen::Vector3f::UnitZ() * -5.f;
+ glLoadMatrixf(trafo.data());
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_INDEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glIndexPointer(GL_UNSIGNED_INT, 0, indices.data());
+ glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
+ glTexCoordPointer(2, GL_FLOAT, 0, texCoords.constData());
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, indices.data());
+}
+
+void NavBallView::setQuaternion(const QQuaternion& q)
+{
+// std::cout << "setQuaternion([" << q.x() << ' ' << q.y() << ' ' << q.z() << ", " << q.scalar() << "]\n";
+ quat.w() = q.scalar();
+ quat.x() = q.x();
+ quat.y() = q.y();
+ quat.z() = q.z();
+ updateGL();
+}
+
+
+void NavBallView::makeSphere()
+{
+ QPixmap pixmap(QString(":/nav_ball/navball.png"));
+// std::cout << "Image: " << pixmap.size().height() << " x " << pixmap.size().width() << '\n';
+ texture = bindTexture(pixmap, GL_TEXTURE_2D);
+ const int meridians = 32, latitudes = 15;
+ vertices.reserve((meridians+1) * (latitudes+2));
+ texCoords.reserve((meridians+1) * (latitudes+2));
+
+ for (int i = 0; i < meridians + 1; ++i) {
+ for (int j = 0; j < latitudes + 2; ++j) {
+ // texture coordinates in [0,1] x [0,1]:
+ texCoords.append(QVector2D(double(i)/meridians, double(j)/(latitudes+1)));
+
+ // theta = longitude from 0 to 2*pi
+ // phi = latitude from -pi/2 to pi/2
+ double theta = 2*M_PI * (texCoords.back().x());
+ double phi = M_PI * (texCoords.back().y() - 0.5);
+ vertices.append( QVector3D(
+ std::cos(phi) * std::cos(theta),
+ std::cos(phi) * std::sin(theta),
+ std::sin(phi)
+ ));
+ }
+ }
+
+ for (int i = 0; i < meridians; ++i)
+ {
+ // Construct triangles between successive meridians
+ for (int j = 0; j < latitudes + 1; ++j)
+ {
+ indices.push_back((i+1) * (latitudes+2) + j+1);
+ indices.push_back(i * (latitudes+2) + j+1);
+ indices.push_back(i * (latitudes+2) + j);
+
+ indices.push_back(i * (latitudes+2) + j);
+ indices.push_back((i+1) * (latitudes+2) + j);
+ indices.push_back((i+1) * (latitudes+2) + j+1);
+ }
+ }
+// std::cout << "Made sphere, vertices: " << vertices.size() << ", indices: " << indices.size() << '\n';
+}
+
diff --git a/src/nav_ball/navball.h b/src/nav_ball/navball.h
new file mode 100644
index 0000000..f649351
--- /dev/null
+++ b/src/nav_ball/navball.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include
+#include
+
+#include
+
+#include
+
+class QWidget;
+
+class NavBallView : public QGLWidget
+{
+ Q_OBJECT
+ Q_CLASSINFO("Author", "Christoph Hertzberg")
+
+public:
+ NavBallView(QWidget *parent=NULL);
+ // virtual ~Orientation(); //Attention if you comment in this the widgets are not longer visible in designer WTF?
+ void paintEvent(QPaintEvent *) {paintGL();}
+ void resizeEvent ( QResizeEvent * event ) {QGLWidget::resizeEvent(event);}
+
+public slots:
+
+ NavBallView* newInstance() { return new NavBallView; } // TODO why?
+ void setQuaternion(const QQuaternion& q);
+ void update() const {}; //Nothing needs to be done but needs to be implemented for ruby bindings
+
+protected:
+ void initializeGL();
+ void paintGL();
+ void resizeGL(int width, int height);
+private:
+ void makeSphere();
+
+ GLuint texture;
+ QVector vertices;
+ QVector texCoords;
+ std::vector indices;
+
+ Eigen::Quaternion quat, nwu2gl;
+};
+
diff --git a/src/nav_ball/navballplugin.cc b/src/nav_ball/navballplugin.cc
new file mode 100644
index 0000000..bb64ee6
--- /dev/null
+++ b/src/nav_ball/navballplugin.cc
@@ -0,0 +1,84 @@
+#include "navballplugin.h"
+#include "navball.h"
+
+ NavBallPlugin::NavBallPlugin(QObject *parent) : QObject(parent)
+ {
+ initialized = false;
+ }
+
+ NavBallPlugin::~NavBallPlugin()
+ {
+ }
+
+ void NavBallPlugin::initialize(QDesignerFormEditorInterface *formEditor)
+ {
+ if (initialized)
+ return;
+ initialized = true;
+ }
+
+ bool NavBallPlugin::isInitialized() const
+ {
+ return initialized;
+ }
+
+ QWidget *NavBallPlugin::createWidget(QWidget *parent)
+ {
+ return new NavBallView(parent);
+ }
+
+ QString NavBallPlugin::name() const
+ {
+ return "NavBallView";
+ }
+
+ QString NavBallPlugin::group() const
+ {
+ return "Rock-Robotics";
+ }
+
+ QIcon NavBallPlugin::icon() const
+ {
+ return QIcon(":/artificial_horizon/icon.png");
+ }
+
+ QString NavBallPlugin::toolTip() const
+ {
+ return "Widget for displaying an Orientation";
+ }
+
+ QString NavBallPlugin::whatsThis() const
+ {
+ return "Widget for displaying an Orientation";
+ }
+
+ bool NavBallPlugin::isContainer() const
+ {
+ return false;
+ }
+
+ QString NavBallPlugin::domXml() const
+ {
+ return "\n"
+ " \n"
+ " \n"
+ " 0\n"
+ " 0\n"
+ " 150\n"
+ " 150\n"
+ " \n"
+ " \n"
+ " \n"
+ " NavBallView\n"
+ " \n"
+ " \n"
+ " \n"
+ " \n"
+ "\n";
+ }
+
+ QString NavBallPlugin::includeFile() const
+ {
+ return "rock_widget_collection/navball.h";
+ }
+
diff --git a/src/nav_ball/navballplugin.h b/src/nav_ball/navballplugin.h
new file mode 100644
index 0000000..85f48b3
--- /dev/null
+++ b/src/nav_ball/navballplugin.h
@@ -0,0 +1,30 @@
+
+#pragma once
+
+#include
+#include
+
+class NavBallPlugin : public QObject , public QDesignerCustomWidgetInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+
+ public:
+ NavBallPlugin(QObject *parent = 0);
+ virtual ~NavBallPlugin();
+
+ bool isContainer() const;
+ bool isInitialized() const;
+ QIcon icon() const;
+ QString domXml() const;
+ QString group() const;
+ QString includeFile() const;
+ QString name() const;
+ QString toolTip() const;
+ QString whatsThis() const;
+ QWidget *createWidget(QWidget *parent);
+ void initialize(QDesignerFormEditorInterface *core);
+
+ private:
+ bool initialized;
+};
diff --git a/src/nav_ball/resources/navball.png b/src/nav_ball/resources/navball.png
new file mode 100644
index 0000000..d81e1e1
Binary files /dev/null and b/src/nav_ball/resources/navball.png differ
diff --git a/src/resources.qrc b/src/resources.qrc
index 218f3f3..3d8ca3e 100644
--- a/src/resources.qrc
+++ b/src/resources.qrc
@@ -13,5 +13,6 @@
timeline/resources/icon.png
progress_indicator/resources/icon.png
virtual_joystick/resources/icon.png
+ nav_ball/resources/navball.png