The triSetConstraint example

triSetConstraint

A TriangleSetConstraint constrains the camera displacement.

The camera is constrained to stay above a given 'road' defined by triangles. Camera is in FLY mode.

The example is a little bit complex : the computations needed to get the intersection of the Z-direction and the triangle are cut and pasted from the triangleSetConstraint class, in order to draw interesting debugging informations.

triSetConstraint.h


#include <QGLViewer/qglviewer.h>

class Viewer : public QGLViewer
{
protected :
  void init();
  void draw();
  void displayConstraint(qglviewer::Vec);
};

triSetConstraint.cpp


#include "triSetConstraint.h"
#include <QGLViewer/triangleSetConstraint.h>
#include <math.h>

using namespace qglviewer;


static bool segmentIntersection(const Vec& p, const Vec& dir1, const Vec& norm,
				const Vec& s1, const Vec& s2,
				Vec& inter)
{
  // dir1 is supposed to be normalized.
  Vec perp = cross(dir1, norm);

  // Check for near-parallel lines
  float n = perp.norm();

  // Degenerated case : parallel lines
  if (n < 1.E-10)
    return false;

  perp /= n;

  float proj = (s2 - s1) * perp;
  float alpha = ((p-s1)*perp) / proj;
  if ( (alpha < 0.0) || (alpha > 1.0) )
    return false;

  // else
  inter = s1 + (s2-s1) * alpha;
  return true;
}


/* Constrain the translation \p trans with respect to a path defined by a triangle set. See addTriangle() and addPoint(). */
void Viewer::displayConstraint(Vec trans)
{
  TriangleSetConstraint* tsc = (TriangleSetConstraint*)(camera()->frame()->constraint());
  unsigned int currentTriangle = tsc->currentTriangle();
  trans = camera()->frame()->inverseTransformOf(trans);
  Vec pos, nextPos, start;
  start = camera()->position();
  pos = start;
  unsigned short nextEdge;
  const float dist = trans.norm();
  if (dist < 1E-8)
    return;
  trans /= dist;

  // Draw the current triangle
  glColor3f(.6,.2,6);
  glLineWidth(4.0);
  glBegin(GL_TRIANGLES);
  glVertex3fv(tsc->point(tsc->trianglePoint(currentTriangle,0)).address());
  glVertex3fv(tsc->point(tsc->trianglePoint(currentTriangle,1)).address());
  glVertex3fv(tsc->point(tsc->trianglePoint(currentTriangle,2)).address());
  glEnd();

  glColor3f(.8,.5,0);
  glPointSize(10.0);
  glBegin(GL_POINTS); glVertex3fv(start.address()); glEnd();
  glLineWidth(1.0);
  glBegin(GL_LINES); glVertex3fv(start.address()); glVertex3fv((start+trans).address()); glEnd();

  glColor3f(.4,.6,.7);
  glPointSize(5.0);

  while (true)
    {
      float step = -1.0E9f;
      nextEdge = 3;
      Vec e1 = tsc->point(tsc->trianglePoint(currentTriangle,0)) - tsc->point(tsc->trianglePoint(currentTriangle,1));
      Vec e2 = tsc->point(tsc->trianglePoint(currentTriangle,0)) - tsc->point(tsc->trianglePoint(currentTriangle,2));
      Vec norm = cross(e1, e2);
      Vec res;

      for (unsigned short edge=0; edge<3; edge++)
	{
	  if (segmentIntersection(pos, trans, norm,
				  tsc->point(tsc->trianglePoint(currentTriangle,(edge+1)%3)),
				  tsc->point(tsc->trianglePoint(currentTriangle,(edge+2)%3)), res))
	    {
	      if ((res-pos)*trans > step)
		{
		  step = (res-pos)*trans;
		  nextPos = res;
		  nextEdge = edge;
		}
	    }
	}

      glBegin(GL_POINTS); glVertex3fv(nextPos.address()); glEnd();

      float soFar = (nextPos-start)*trans;
      if ((soFar > dist) || (tsc->neighTriangle(currentTriangle,nextEdge) == -1))
	return;

      currentTriangle = tsc->neighTriangle(currentTriangle,nextEdge);

      pos = nextPos;
    }
}

static const float nbSteps = 20.0;
static const float r = 0.7;

void Viewer::init()
{
  setSceneRadius(3.0);
  camera()->setFlySpeed(0.001);
  // Use fly mode mouse bindings
  toggleCameraMode();
  glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

  TriangleSetConstraint* tsc = new TriangleSetConstraint();
  camera()->frame()->setConstraint(tsc);

  tsc->addPoint(Vec(1.0,0.0,0.0));
  tsc->addPoint(Vec(r   ,0.0,0.0));
  for (int i=1; i<nbSteps; ++i)
    {
      float angle = 2.0 * M_PI * i / nbSteps;
      tsc->addPoint(Vec(cos(angle)  , sin(angle)  , 0.0)); // index 2i
      tsc->addPoint(Vec(r*cos(angle), r*sin(angle), 0.0)); // index 2i+1

      tsc->addTriangle(2*i-1, 2*i, 2*i+1);
      tsc->addTriangle(2*i-1, 2*i-2, 2*i);
    }
  tsc->addTriangle(0, 2*(int)nbSteps-2, 2*(int)nbSteps-1);
  tsc->addTriangle(0, 1, 2*(int)nbSteps-1);
  tsc->setCurrentTriangle(1);

  camera()->setOrientation(Quaternion(Vec(1,0,0), M_PI/2.0));
  camera()->setPosition(0.85, 0.05, 0.0);
}

void Viewer::draw()
{
  // The camera is made visible by reseting the modelview matrix
  glLoadIdentity();
  glTranslatef(0.0,0.0,-2.5);

  // Draw Road
  glNormal3f(0.0, 0.0, 1.0);
  glColor3f(.2,.6,.8);

  glBegin(GL_QUAD_STRIP);
  for (float i=0; i<=nbSteps; ++i)
    {
      float angle = 2.0 * M_PI * i / nbSteps;
      glVertex3f(cos(angle),   sin(angle),   0.0);
      glVertex3f(r*cos(angle), r*sin(angle), 0.0);
    }
  glEnd();

  // Draw camera position
  Vec pos = camera()->position();
  glPointSize(5.0);
  glBegin(GL_POINTS);
  glVertex3fv(pos.address());
  glEnd();

  displayConstraint(Vec(0,0,-1));
}

main.cpp


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

int main(int argc, char** argv)
{
  // Read command lines arguments.
  QApplication application(argc,argv);

  // Instantiate the viewer.
  Viewer v;

  // Make the viewer window visible on screen.
  v.show();

  // Set the viewer as the application main widget.
  application.setMainWidget(&v);

  // Run main loop.
  return application.exec();
}

Go back to the examples main page

Valid XHTML 1.0! Valid CSS! Last modified on Friday, November 7, 2003.