From 4e9be1cfcdcdcbc5792b2b9262c0f697e1820ea0 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 18 Nov 2008 23:22:31 +0000 Subject: [PATCH] Mouse control --- geo/tcElevationData.cpp | 12 +++--- geo/tcGeo.h | 14 +++++++ geo/tcGlobe.cpp | 10 +++++ geo/tcGlobe.h | 7 ++++ geo/tcObserver.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ geo/tcObserver.h | 50 +++++++++++++++++++++++ maths/glVector.h | 98 +++++++++++++++++++++++++++++++++++++++++++++ tcViewportWidget.cpp | 74 +++++++++++++++++++++++++++------- tcViewportWidget.h | 27 +++++++++++++ 9 files changed, 374 insertions(+), 22 deletions(-) create mode 100644 maths/glVector.h diff --git a/geo/tcElevationData.cpp b/geo/tcElevationData.cpp index e5a530a..bf57b34 100644 --- a/geo/tcElevationData.cpp +++ b/geo/tcElevationData.cpp @@ -24,6 +24,7 @@ #include "tcElevationData.h" #include "tcSrtmData.h" +#include #include @@ -53,11 +54,11 @@ void tcElevationData::renderSchematic(double meanRadius) { tcGeoData::renderSchematic(meanRadius); - for (int i = 0; i < m_srtm->lines(); i += 5) + for (int i = 0; i < m_srtm->lines(); i += 2) { glBegin(GL_LINE_STRIP); { - for (int j = 0; j < m_srtm->length(); j += 1) + for (int j = 0; j < m_srtm->length(); j += 2) { uint32_t alt = m_srtm->pixelAltitude(i,j); if (alt == 32768) @@ -67,13 +68,10 @@ void tcElevationData::renderSchematic(double meanRadius) continue; } tcGeo coord = m_srtm->pixelCoordinate(i,j); + GLvec3d dir = coord; double rad = meanRadius + alt; - double z = cos(coord.lat()); - double xy = sin(coord.lat()); glColor3f(1.0f, 1.0f-(float)alt/3278.0f, 0.0f); - glVertex3d(rad*sin(coord.lon())*xy, - rad*cos(coord.lon())*xy, - rad*z); + glVertex3(dir * rad); } } glEnd(); diff --git a/geo/tcGeo.h b/geo/tcGeo.h index 9b5b6b3..594e7cf 100644 --- a/geo/tcGeo.h +++ b/geo/tcGeo.h @@ -25,6 +25,8 @@ * @brief Geographical coordinates. */ +#include + /// Use doubles for angles. typedef double tcGeoAngle; @@ -52,6 +54,18 @@ class tcGeo } /* + * Conversions + */ + + /// Convert to a 3d direction vector. + operator maths::Vector<3,double> () const + { + double z = sin(m_latitude); + double xy = cos(m_latitude); + return maths::Vector<3,double>(xy*sin(m_longitude), xy*cos(m_longitude), z); + } + + /* * Accessors */ diff --git a/geo/tcGlobe.cpp b/geo/tcGlobe.cpp index d405aed..51b6d64 100644 --- a/geo/tcGlobe.cpp +++ b/geo/tcGlobe.cpp @@ -107,3 +107,13 @@ void tcGlobe::render(tcObserver* observer) data->renderSchematic(m_meanRadius); } } + +/* + * Accessors + */ + +/// Get the mean radius. +double tcGlobe::meanRadius() const +{ + return m_meanRadius; +} diff --git a/geo/tcGlobe.h b/geo/tcGlobe.h index bf97b4b..4275bdd 100644 --- a/geo/tcGlobe.h +++ b/geo/tcGlobe.h @@ -62,6 +62,13 @@ class tcGlobe /// Render from the POV of an observer. void render(tcObserver* observer); + /* + * Accessors + */ + + /// Get the mean radius. + double meanRadius() const; + private: /* diff --git a/geo/tcObserver.cpp b/geo/tcObserver.cpp index a31bfa0..94c58e5 100644 --- a/geo/tcObserver.cpp +++ b/geo/tcObserver.cpp @@ -24,12 +24,20 @@ #include "tcObserver.h" +#include + +#include + /* * Constructors + destructor */ /// Primary constructor. tcObserver::tcObserver() +: m_focus(0.0, 0.0) +, m_focusAltitude(1000e3) +, m_view(M_PI*0/4, -M_PI*1/2) +, m_range(100e3) { } @@ -37,3 +45,99 @@ tcObserver::tcObserver() tcObserver::~tcObserver() { } + +/* + * Main interface + */ + +/// Set up the OpenGL projection matrix for this observer. +void tcObserver::setupProjection(double aspect) const +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + #define SIZE 80.0 + glFrustum(SIZE*aspect, -SIZE*aspect, -SIZE, SIZE, 100.0, 1000e3); + glMatrixMode(GL_MODELVIEW); +} + +/// Set up the OpenGL modelview matrix for this observer. +void tcObserver::setupModelView() const +{ + glLoadIdentity(); + + // Translate to focus + glTranslatef(0.0f, 0.0f, -m_range); + + // Rotate into focus orientation + glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); + glRotatef(-m_view.elev() * 180.0f/M_PI, 1.0f, 0.0f, 0.0f); + glRotatef(-m_view.azim() * 180.0f/M_PI, 0.0f, 0.0f, -1.0f); + + // Translate to origin + glTranslatef(0.0f, 0.0f, -m_focusAltitude); + + // Rotate to model orientation + glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); + glRotatef(m_focus.lat() * 180.0f/M_PI, 1.0f, 0.0f, 0.0f); + glRotatef(-180.0f, 0.0f, 0.0f, 1.0f); + glRotatef(m_focus.lon() * 180.0f/M_PI, 0.0f, 0.0f, 1.0f); + + glBegin(GL_LINES); + { + glColor3f(1.0, 1.0, 1.0); + glVertex3f(0, 0, 0); + glColor3f(1.0, 0.0, 0.0); + glVertex3f(5000e3, 0, 0); + + glColor3f(1.0, 1.0, 1.0); + glVertex3f(0, 0, 0); + glColor3f(0.0, 1.0, 0.0); + glVertex3f(0, 5000e3, 0); + + glColor3f(1.0, 1.0, 1.0); + glVertex3f(0, 0, 0); + glColor3f(0.0, 0.0, 1.0); + glVertex3f(0, 0, 5000e3); + } + glEnd(); +} + +/* + * Mutators + */ + +/// Adjust the focus directly. +void tcObserver::setFocus(const tcGeo& focus, double altitude) +{ + m_focus = focus; + m_focusAltitude = altitude; +} + +/// Make a local transformation of the focus. +void tcObserver::moveFocusRelative(double dx, double dy) +{ + dx *= 2.0 * m_range / m_focusAltitude; + dy *= 2.0 * m_range / m_focusAltitude; + m_focus.setLat(m_focus.lat() - sin(m_view.azim()) * dx + + cos(m_view.azim()) * dy); + m_focus.setLon(m_focus.lon() - cos(m_view.azim()) * dx + - sin(m_view.azim()) * dy); +} + +/// Adjust the range exponentially. +void tcObserver::adjustRange(double x) +{ + m_range *= exp(x); +} + +/// Adjust the azimuth in radians. +void tcObserver::adjustAzimuth(double daz) +{ + m_view.setAzim(m_view.azim() + daz); +} + +/// Adjust the elevation in radians. +void tcObserver::adjustElevation(double del) +{ + m_view.setElev(m_view.elev() + del); +} diff --git a/geo/tcObserver.h b/geo/tcObserver.h index 86033ff..2049e06 100644 --- a/geo/tcObserver.h +++ b/geo/tcObserver.h @@ -25,6 +25,9 @@ * @brief Viewing information for an observer. */ +#include "tcGeo.h" +#include "tcGeoVector.h" + /// Viewing information for an observer. class tcObserver { @@ -39,6 +42,53 @@ class tcObserver /// Destructor. virtual ~tcObserver(); + + /* + * Main interface + */ + + /// Set up the OpenGL projection matrix for this observer. + void setupProjection(double aspect) const; + + /// Set up the OpenGL modelview matrix for this observer. + void setupModelView() const; + + /* + * Mutators + */ + + /// Adjust the focus directly. + void setFocus(const tcGeo& focus, double altitude); + + /// Make a local transformation of the focus. + void moveFocusRelative(double dx, double dy); + + /// Adjust the range exponentially. + void adjustRange(double x); + + /// Adjust the azimuth in radians. + void adjustAzimuth(double daz); + + /// Adjust the elevation in radians. + void adjustElevation(double del); + + private: + + /* + * Variables + */ + + /// Geographical position of focus. + tcGeo m_focus; + + /// Altitude of focus. + double m_focusAltitude; + + /// Observation direction. + tcGeoVector m_view; + + /// Range of camera. + double m_range; }; #endif diff --git a/maths/glVector.h b/maths/glVector.h new file mode 100644 index 0000000..bee7ca4 --- /dev/null +++ b/maths/glVector.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * This file is part of Tecorrec. * + * Copyright 2008 James Hogan * + * * + * Tecorrec 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 2 of the License, or * + * (at your option) any later version. * + * * + * Tecorrec 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 Tecorrec. If not, write to the Free Software Foundation, * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef _maths_glVector_h +#define _maths_glVector_h + +/* + * maths::gl::vec.h + * + * Inline function helpers for maths::gl::vec classes (from maths library) + * These are overloaded to take multiple data types + */ + +#include +#include + +namespace maths { + namespace gl { + // Make use of maths library vector classes + typedef maths::Vector<2,GLfloat> vec2f; + typedef maths::Vector<3,GLfloat> vec3f; + typedef maths::Vector<4,GLfloat> vec4f; + typedef maths::Vector<2,GLdouble> vec2d; + typedef maths::Vector<3,GLdouble> vec3d; + typedef maths::Vector<4,GLdouble> vec4d; + } // ::maths::gl +} // ::maths + +typedef maths::gl::vec2f GLvec2f; +typedef maths::gl::vec3f GLvec3f; +typedef maths::gl::vec4f GLvec4f; +typedef maths::gl::vec2d GLvec2d; +typedef maths::gl::vec3d GLvec3d; +typedef maths::gl::vec4d GLvec4d; + +// Send a two dimentional vertex to OpenGL +inline void glVertex2(const maths::gl::vec2f & v) { glVertex2fv(v); } +inline void glVertex2(const maths::gl::vec2d & v) { glVertex2dv(v); } + +// Send a three dimentional vertex to OpenGL +inline void glVertex3(const maths::gl::vec3f & v) { glVertex3fv(v); } +inline void glVertex3(const maths::gl::vec3d & v) { glVertex3dv(v); } + +// Send a four dimentional vertex to OpenGL +inline void glVertex4(const maths::gl::vec4f & v) { glVertex4fv(v); } +inline void glVertex4(const maths::gl::vec4d & v) { glVertex4dv(v); } + +// Send a normal vector to OpenGL +inline void glNormal(const maths::gl::vec3f & v) { glNormal3fv(v); } +inline void glNormal(const maths::gl::vec4f & v) { glNormal3fv(v); } +inline void glNormal(const maths::gl::vec3d & v) { glNormal3dv(v); } +inline void glNormal(const maths::gl::vec4d & v) { glNormal3dv(v); } + +// Send a two dimentional texture coordinate to OpenGL +inline void glTexCoord2(const maths::gl::vec2f & v) { glTexCoord2fv(v); } +inline void glTexCoord2(const maths::gl::vec2d & v) { glTexCoord2dv(v); } + +// Send a three dimentional texture coordinate to OpenGL +inline void glTexCoord3(const maths::gl::vec3f & v) { glTexCoord3fv(v); } +inline void glTexCoord3(const maths::gl::vec3d & v) { glTexCoord3dv(v); } + +// Send a two dimentional mulitexture coordinate to OpenGL +inline void glMultiTexCoord2(GLenum target, const maths::gl::vec2f & v) { glMultiTexCoord2fv(target, v); } +inline void glMultiTexCoord2(GLenum target, const maths::gl::vec2d & v) { glMultiTexCoord2dv(target, v); } + +// Send a three dimentional mulitexture coordinate to OpenGL +inline void glMultiTexCoord3(GLenum target, const maths::gl::vec3f & v) { glMultiTexCoord3fv(target, v); } +inline void glMultiTexCoord3(GLenum target, const maths::gl::vec3d & v) { glMultiTexCoord3dv(target, v); } + +// Translate the modelview matrix by a vector +inline void glTranslate(const maths::gl::vec2f & v, GLfloat z = 0.0f) { glTranslatef(v[0], v[1], z); } +inline void glTranslate(const maths::gl::vec3f & v) { glTranslatef(v[0], v[1], v[2]); } +inline void glTranslate(const maths::gl::vec4f & v) { glTranslatef(v[0], v[1], v[2]); } +inline void glTranslate(const maths::gl::vec2d & v, GLdouble z = 0.0 ) { glTranslated(v[0], v[1], z); } +inline void glTranslate(const maths::gl::vec3d & v) { glTranslated(v[0], v[1], v[2]); } +inline void glTranslate(const maths::gl::vec4d & v) { glTranslated(v[0], v[1], v[2]); } + +// Rotate the modelview matrix rad radians about axis +inline void glRotate(const float rad, const maths::gl::vec3f & axis) { glRotatef(rad*57.29577951f, axis[0], axis[1], axis[2]); } +inline void glRotate(const double rad, const maths::gl::vec3d & axis) { glRotated(rad*57.29577951, axis[0], axis[1], axis[2]); } + +#endif diff --git a/tcViewportWidget.cpp b/tcViewportWidget.cpp index 7242a04..4ec8422 100644 --- a/tcViewportWidget.cpp +++ b/tcViewportWidget.cpp @@ -26,6 +26,10 @@ #include #include +#include + +#include + /* * Constructors + destructor */ @@ -35,6 +39,8 @@ tcViewportWidget::tcViewportWidget(QWidget* parent) : QGLWidget(parent) , m_observer(new tcObserver()) , m_globe(0) +, m_mouseInteracting(false) +, m_mousePos() { } @@ -52,6 +58,7 @@ tcViewportWidget::~tcViewportWidget() void tcViewportWidget::setGlobe(tcGlobe* globe) { m_globe = globe; + m_observer->setFocus(tcGeo( 7.0 * M_PI/180, 46.0 * M_PI/180), globe->meanRadius()); } /* @@ -60,7 +67,7 @@ void tcViewportWidget::setGlobe(tcGlobe* globe) void tcViewportWidget::initializeGL() { - glClearColor(0.0, 0.5, 1.0, 0.0); + glClearColor(0.0, 0.0, 0.0, 0.0); } void tcViewportWidget::resizeGL(int w, int h) @@ -68,13 +75,7 @@ void tcViewportWidget::resizeGL(int w, int h) glViewport(0, 0, (GLint)w, (GLint)h); double aspect = (double)w / h; - - // Set up the camera - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - #define SIZE 80.0 - glFrustum(-SIZE*aspect, SIZE*aspect, -SIZE, SIZE, 100.0, 20000e3); - glMatrixMode(GL_MODELVIEW); + m_observer->setupProjection(aspect); } void tcViewportWidget::paintGL() @@ -82,15 +83,58 @@ void tcViewportWidget::paintGL() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); - glLoadIdentity(); + m_observer->setupModelView(); + + m_globe->render(m_observer); +} + +/* + * Mouse events + */ - glPushMatrix(); +void tcViewportWidget::mouseMoveEvent(QMouseEvent* event) +{ + if (m_mouseInteracting) { - glTranslatef(0.0f, 0.0f, -6500e3); - glRotatef(-52.5, -1.0f, 0.0f, 0.0f); - glRotatef(9, -1.0f, 0.0f, 1.0f); + QPointF dpos = event->posF() - m_mousePos; + m_mousePos = event->posF(); + + // Pan the scene, adjust the observer focus + m_observer->moveFocusRelative(dpos.x() / height(), dpos.y() / width()); + + updateGL(); + } +} + +void tcViewportWidget::mousePressEvent(QMouseEvent* event) +{ + m_mouseInteracting = true; + m_mousePos = event->posF(); +} + +void tcViewportWidget::mouseReleaseEvent(QMouseEvent* event) +{ + m_mouseInteracting = false; +} - m_globe->render(m_observer); +void tcViewportWidget::wheelEvent(QWheelEvent* event) +{ + float delta = M_PI/180.0 * event->delta()/8; + if (event->orientation() == Qt::Vertical) + { + if (event->modifiers().testFlag(Qt::ControlModifier)) + { + m_observer->adjustElevation(-delta); + } + else + { + m_observer->adjustRange(delta); + } } - glPopMatrix(); + else + { + m_observer->adjustAzimuth(delta); + } + + updateGL(); } diff --git a/tcViewportWidget.h b/tcViewportWidget.h index b4773df..0d699cf 100644 --- a/tcViewportWidget.h +++ b/tcViewportWidget.h @@ -26,6 +26,7 @@ */ #include +#include class tcObserver; class tcGlobe; @@ -69,6 +70,22 @@ class tcViewportWidget : public QGLWidget // Reimplemented virtual void paintGL(); + /* + * Mouse events + */ + + // Reimplemented + virtual void mouseMoveEvent(QMouseEvent* event); + + // Reimplemented + virtual void mousePressEvent(QMouseEvent* event); + + // Reimplemented + virtual void mouseReleaseEvent(QMouseEvent* event); + + // Reimplemented + virtual void wheelEvent(QWheelEvent* event); + private: /* @@ -80,6 +97,16 @@ class tcViewportWidget : public QGLWidget /// Globe to display. tcGlobe* m_globe; + + /* + * Interaction + */ + + /// Are we currently interacting? + bool m_mouseInteracting; + + /// Previous mouse position. + QPointF m_mousePos; }; #endif -- 2.11.4.GIT