Home Download Gallery Documentation Developer

# The constrainedCamera example

Constraints applied on the Camera Frame to limit its translation and/or rotation.

Try the different possible constraints using the T (translate) and R (rotate) keys. G and D change the constraint directions. Press Space to change the coordinate system (World or Camera) which defines the constraint directions.

Note that in order to apply a constraint to a camera, you need to apply it to the camera()->frame().

## constrainedCamera.h

    #include <QGLViewer/qglviewer.h>

    class Viewer : public QGLViewer {
    protected:
      virtual void init();
      virtual void draw();
      virtual QString helpString() const;
      virtual void keyPressEvent(QKeyEvent *);

      void displayText();
      void displayType(const qglviewer::AxisPlaneConstraint::Type type, const int x,
                       const int y, const char c);
      void displayDir(const unsigned short dir, const int x, const int y,
                      const char c);

    private:
      int transDir;
      int rotDir;

      static qglviewer::AxisPlaneConstraint::Type nextTranslationConstraintType(
          const qglviewer::AxisPlaneConstraint::Type &type);
      static qglviewer::AxisPlaneConstraint::Type
      nextRotationConstraintType(const qglviewer::AxisPlaneConstraint::Type &type);

      void changeConstraint();
      qglviewer::AxisPlaneConstraint *constraints[2];
      unsigned short activeConstraint;
    };

## constrainedCamera.cpp

    #include "constrainedCamera.h"

    #include <QGLViewer/manipulatedCameraFrame.h>
    #include <QKeyEvent>

    using namespace qglviewer;
    using namespace std;

    AxisPlaneConstraint::Type
    Viewer::nextTranslationConstraintType(const AxisPlaneConstraint::Type &type) {
      switch (type) {
      case AxisPlaneConstraint::FREE:
        return AxisPlaneConstraint::PLANE;
        break;
      case AxisPlaneConstraint::PLANE:
        return AxisPlaneConstraint::AXIS;
        break;
      case AxisPlaneConstraint::AXIS:
        return AxisPlaneConstraint::FORBIDDEN;
        break;
      case AxisPlaneConstraint::FORBIDDEN:
        return AxisPlaneConstraint::FREE;
        break;
      default:
        return AxisPlaneConstraint::FREE;
      }
    }

    AxisPlaneConstraint::Type
    Viewer::nextRotationConstraintType(const AxisPlaneConstraint::Type &type) {
      switch (type) {
      case AxisPlaneConstraint::FREE:
        return AxisPlaneConstraint::AXIS;
        break;
      case AxisPlaneConstraint::PLANE:
        return AxisPlaneConstraint::FREE;
        break;
      case AxisPlaneConstraint::AXIS:
        return AxisPlaneConstraint::FORBIDDEN;
        break;
      case AxisPlaneConstraint::FORBIDDEN:
        return AxisPlaneConstraint::FREE;
        break;
      default:
        return AxisPlaneConstraint::FREE;
      }
    }

    void Viewer::changeConstraint() {
      unsigned short previous = activeConstraint;
      activeConstraint = (activeConstraint + 1) % 2;

      constraints[activeConstraint]->setTranslationConstraintType(
          constraints[previous]->translationConstraintType());
      constraints[activeConstraint]->setTranslationConstraintDirection(
          constraints[previous]->translationConstraintDirection());
      constraints[activeConstraint]->setRotationConstraintType(
          constraints[previous]->rotationConstraintType());
      constraints[activeConstraint]->setRotationConstraintDirection(
          constraints[previous]->rotationConstraintDirection());

      camera()->frame()->setConstraint(constraints[activeConstraint]);
    }

    void Viewer::init() {
      restoreStateFromFile();

      constraints[0] = new WorldConstraint();

      // Note that a CameraConstraint(camera) would produce the same results:
      // A CameraConstraint is a LocalConstraint when applied to the camera frame !
      constraints[1] = new LocalConstraint();

      transDir = 0;
      rotDir = 0;
      activeConstraint = 0;

      camera()->frame()->setConstraint(constraints[activeConstraint]);

      setAxisIsDrawn();

      setKeyDescription(Qt::Key_G, "Change translation constraint direction");
      setKeyDescription(Qt::Key_D, "Change rotation constraint direction");
      setKeyDescription(Qt::Key_Space, "Change constraint reference");
      setKeyDescription(Qt::Key_T, "Change translation constraint type");
      setKeyDescription(Qt::Key_R, "Change rotation constraint type");

      help();
    }

    void Viewer::draw() {
      const float nbSteps = 200.0;
      glBegin(GL_QUAD_STRIP);
      for (float i = 0; i < nbSteps; ++i) {
        float ratio = i / nbSteps;
        float angle = 21.0 * ratio;
        float c = cos(angle);
        float s = sin(angle);
        float r1 = 1.0 - 0.8 * ratio;
        float r2 = 0.8 - 0.8 * ratio;
        float alt = ratio - 0.5;
        const float nor = .5;
        const float up = sqrt(1.0 - nor * nor);
        glColor3f(1 - ratio, 0.2f, ratio);
        glNormal3f(nor * c, up, nor * s);
        glVertex3f(r1 * c, alt, r1 * s);
        glVertex3f(r2 * c, alt + 0.05, r2 * s);
      }
      glEnd();

      displayText();
    }

    void Viewer::keyPressEvent(QKeyEvent *e) {
      switch (e->key()) {
      case Qt::Key_G:
        transDir = (transDir + 1) % 3;
        break;
      case Qt::Key_D:
        rotDir = (rotDir + 1) % 3;
        break;
      case Qt::Key_Space:
        changeConstraint();
        break;
      case Qt::Key_T:
        constraints[activeConstraint]->setTranslationConstraintType(
            nextTranslationConstraintType(
                constraints[activeConstraint]->translationConstraintType()));
        break;
      case Qt::Key_R:
        constraints[activeConstraint]->setRotationConstraintType(
            nextRotationConstraintType(
                constraints[activeConstraint]->rotationConstraintType()));
        break;
      default:
        QGLViewer::keyPressEvent(e);
      }

      Vec dir(0.0, 0.0, 0.0);
      dir[transDir] = 1.0;
      constraints[activeConstraint]->setTranslationConstraintDirection(dir);

      dir = Vec(0.0, 0.0, 0.0);
      dir[rotDir] = 1.0;
      constraints[activeConstraint]->setRotationConstraintDirection(dir);

      update();
    }

    void Viewer::displayType(const AxisPlaneConstraint::Type type, const int x,
                             const int y, const char c) {
      QString text;
      switch (type) {
      case AxisPlaneConstraint::FREE:
        text = QString("FREE (%1)").arg(c);
        break;
      case AxisPlaneConstraint::PLANE:
        text = QString("PLANE (%1)").arg(c);
        break;
      case AxisPlaneConstraint::AXIS:
        text = QString("AXIS (%1)").arg(c);
        break;
      case AxisPlaneConstraint::FORBIDDEN:
        text = QString("FORBIDDEN (%1)").arg(c);
        break;
      }
      drawText(x, y, text);
    }

    void Viewer::displayDir(const unsigned short dir, const int x, const int y,
                            const char c) {
      QString text;
      switch (dir) {
      case 0:
        text = QString("X (%1)").arg(c);
        break;
      case 1:
        text = QString("Y (%1)").arg(c);
        break;
      case 2:
        text = QString("Z (%1)").arg(c);
        break;
      }
      drawText(x, y, text);
    }

    void Viewer::displayText() {
      glColor4f(foregroundColor().redF(), foregroundColor().greenF(),
                foregroundColor().blueF(), foregroundColor().alphaF());
      glDisable(GL_LIGHTING);
      drawText(10, height() - 30, "TRANSLATION :");
      displayDir(transDir, 190, height() - 30, 'G');
      displayType(constraints[activeConstraint]->translationConstraintType(), 10,
                  height() - 60, 'T');

      drawText(width() - 220, height() - 30, "ROTATION :");
      displayDir(rotDir, width() - 100, height() - 30, 'D');
      displayType(constraints[activeConstraint]->rotationConstraintType(),
                  width() - 220, height() - 60, 'R');

      switch (activeConstraint) {
      case 0:
        drawText(20, 20, "Constraint direction defined w/r to WORLD (SPACE)");
        break;
      case 1:
        drawText(20, 20, "Constraint direction defined w/r to CAMERA (SPACE)");
        break;
      }

      glEnable(GL_LIGHTING);
    }

    QString Viewer::helpString() const {
      QString text("<h2>C o n s t r a i n e d C a m e r a</h2>");
      text += "The camera frame can be constrained to limit the camera "
              "displacements.<br><br>";
      text += "Try the different translation (press <b>G</b> and <b>T</b>) and "
              "rotation ";
      text += "(<b>D</b> and <b>R</b>) constraints while moving the camera with "
              "the mouse. ";
      text += "The constraints can be defined with respect to various coordinates ";
      text += "systems : press <b>Space</b> to switch.<br><br>";
      text += "You can easily define your own constraints to create a specific "
              "camera constraint.";
      return text;
    }

## main.cpp

    #include "constrainedCamera.h"
    #include <qapplication.h>

    int main(int argc, char **argv) {
      QApplication application(argc, argv);

      Viewer viewer;

      viewer.setWindowTitle("constrainedCamera");

      viewer.show();

      return application.exec();
    }

Back to the examples main page.