Sophie

Sophie

distrib > Mandriva > 10.0-com > i586 > by-pkgid > 9347541fe87a5ea3f3b8dbc50f660e8e > files > 168

libQGLViewer-devel-1.3.6-1mdk.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>libQGLViewer select example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <link href="../qglviewer.css" rel="stylesheet" type="text/css" />
  <link rel="shortcut icon" href="../images/qglviewer.ico" type="image/x-icon" />
  <link rel="icon" href="../images/qglviewer.icon.png" type="image/png" />
</head>
<body>

<table class="banner">
  <tr>
     <td align="center"><a href="../index.html"><b>Home</b></a></td>
     <td align="center"><a href="../refManual/hierarchy.html"><b>Documentation</b></a></td>
     <td align="center"><a href="../download.html"><b>Download</b></a></td>
     <td align="center" class="qindexHL"><a href="index.html"><b>Screenshots</b></a></td>
     <td align="center"><a href="../developer.html"><b>Developer</b></a></td>
   </tr>
</table>

<h1>The select example</h1>
<center>
  <img src="../images/select.jpg" width="300" height="200" alt="select"/>
</center>

<p>
 Selection of objects of the scene using <code>select()</code> and an OpenGL GL_SELECT render mode.
</p>
<p>
 Use the <code>select()</code> callback function to implement your object selection function. This
 examples is based on a generic GL_SELECT implementation that can easily be cut and pasted in your
 applications.
</p>
<p>
 Analytic intersection computations are also possible once the screen coordinates have be converted
 to a half line using <code>convertClickToLine()</code>. Make a selection and then move the camera
 to see a representation of the intersection line.
</p>


<h2>select.h</h2>
<pre>

<span class="dir">#include &lt;QGLViewer/qglviewer.h&gt;
</span>
<span class="key">class </span>Viewer : <span class="key">public </span>QGLViewer
{
<span class="key">protected </span>:
  <span class="key">virtual </span><span class="typ">void </span>draw();
  <span class="key">virtual </span><span class="typ">void </span>select(<span class="typ">const </span>QMouseEvent*);
  <span class="key">virtual </span><span class="typ">void </span>init();
  <span class="key">virtual </span>QString helpString() <span class="typ">const</span>;

<span class="key">private </span>:
  qglviewer::Vec orig, dir, selectedPoint;
};</pre>


<h2>select.cpp</h2>
<pre>

<span class="dir">#include </span><span class="dstr">&quot;select.h&quot;</span><span class="dir">
</span><span class="dir">#include &lt;math.h&gt;
</span><span class="dir">#include &lt;limits.h&gt; </span><span class="com">// UINT_MAX
</span><span class="dir"></span>
<span class="key">using namespace </span>std;

<span class="com">// The id of the selected object. Should be encapsulated.
</span><span class="com">// -1 means no object is selected.
</span><span class="typ">static int </span>selected;

<span class="typ">static void </span>drawSpiral(<span class="typ">const bool </span>specialColor = <span class="key">false</span>)
{
  <span class="typ">const float </span>nbSteps = <span class="num">100.0</span>;
  glBegin(GL_QUAD_STRIP);
  <span class="key">for </span>(<span class="typ">float </span>i=<span class="num">0</span>; i&lt;nbSteps; ++i)
    {
      <span class="key">if </span>(specialColor)
	glColor3f((nbSteps-i)/nbSteps, .<span class="num">8 </span>, i/nbSteps/<span class="num">2.0</span>);
      <span class="key">else
	</span>glColor3f((nbSteps-i)/nbSteps, .<span class="num">2 </span>, i/nbSteps);
      <span class="typ">float </span>angle = i/<span class="num">4.0</span>;
      <span class="typ">float </span>c = cos(angle);
      <span class="typ">float </span>s = sin(angle);
      <span class="typ">float </span>r1 = <span class="num">0.5 </span>- i/(<span class="num">3.</span>f*nbSteps);
      <span class="typ">float </span>r2 = <span class="num">0.3 </span>- i/(<span class="num">3.</span>f*nbSteps);
      <span class="typ">float </span>alt = i/nbSteps <span class="num">- 0.5</span>;
      <span class="typ">const float </span>nor = .<span class="num">5</span>;
      <span class="typ">const float </span>up = sqrt(<span class="num">1.0</span>-nor*nor);
      glNormal3f(nor*c, nor*s, up);
      glVertex3f(r1*c, r1*s, alt);
      glVertex3f(r2*c, r2*s, alt+<span class="num">0.05</span>);
    }
  glEnd();
}

<span class="typ">static void </span>drawScene(<span class="typ">bool </span>pushId = <span class="key">false</span>)
{
  <span class="com">// Draw the scene, with a possible pushName() for selection
</span>
  <span class="com">// Consider using several stack levels for different objects, or to separate
</span>  <span class="com">// the triangles, edges and vertices of the same object. Example :
</span>  <span class="com">// glPushName(0)
</span>  <span class="com">//   for all triangles i, glPushName(i), draw triangle, glPopName()
</span>  <span class="com">// glPopName()
</span>  <span class="com">//
</span>  <span class="com">// glPushName(1)
</span>  <span class="com">//   for all edges i, glPushName(i), draw edge, glPopName()
</span>  <span class="com">// glPopName()
</span>  <span class="com">//
</span>  <span class="com">// glPushName(2)
</span>  <span class="com">//   for all vertex i, glPushName(i), raster vertex, glPopName()
</span>  <span class="com">// glPopName()
</span>  <span class="com">// As a result, you have a two level stack, with a type id (0, 1 or 2 here)
</span>  <span class="com">// which indicates the type of the primitive, and then the id of the primitive.
</span>  <span class="com">// See the man page of glSelectBuffer() for details.
</span>
  <span class="typ">const int </span>nb = <span class="num">10</span>;
  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">0</span>; i&lt;nb; ++i)
    {
      glPushMatrix();

      glTranslatef(cos(<span class="num">2.0</span>*i*M_PI/nb), sin(<span class="num">2.0</span>*i*M_PI/nb), <span class="num">0.</span>);

      <span class="key">if </span>(pushId)
	{
	  glPushName(i);
	  drawSpiral();
	  glPopName();
	}
      <span class="key">else
	</span>drawSpiral(i==selected);

      glPopMatrix();
    }
}


<span class="typ">void </span>Viewer::select(<span class="typ">const </span>QMouseEvent* e)
{
  <span class="com">// You should cut-paste this rather tricky function as your own &quot;select()&quot; function.
</span>  <span class="com">// You need a drawing function that pushes and pops names to tag objects' id (see drawSpiral() above).
</span>  <span class="com">// You have to change the call to the drawWithPush (here a simple drawScene()).
</span>  <span class="com">// &quot;selected&quot; is set to the closest object that was picked (or -1 if no object was selected)
</span>
  <span class="com">// Make openGL context current
</span>  makeCurrent();

  <span class="typ">const int </span>SENSITIVITY = <span class="num">4</span>;
  <span class="typ">const int </span>NB_HITS_MAX = <span class="num">64</span>;

  <span class="com">// Prepare the selection mode
</span>  <span class="typ">static </span>GLuint hits[NB_HITS_MAX];

  glSelectBuffer(NB_HITS_MAX, hits);
  glRenderMode(GL_SELECT);
  glInitNames();

  <span class="com">// Loads the matrices
</span>  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  GLint viewport[<span class="num">4</span>];
  camera()-&gt;getViewport(viewport);
  gluPickMatrix(<span class="key">static_cast</span>&lt;GLdouble&gt;(e-&gt;x()), <span class="key">static_cast</span>&lt;GLdouble&gt;(e-&gt;y()), SENSITIVITY, SENSITIVITY, viewport);

  <span class="com">// loadProjectionMatrix() first resets the GL_PROJECTION matrix with a glLoadIdentity.
</span>  <span class="com">// Give false as a parameter in order to prevent this and to combine the matrices.
</span>  camera()-&gt;loadProjectionMatrix(<span class="key">false</span>);
  camera()-&gt;loadModelViewMatrix();

  <span class="com">// Render scene with objects ids.
</span>  <span class="com">// Change here to call your own &quot;drawWithPush()&quot; function.
</span>  drawScene(<span class="key">true</span>);
  glFlush();

  <span class="com">// Get the number of objects were seen through the pick matrix frustum. Reset GL_RENDER mode.
</span>  GLint nb_hits = glRenderMode(GL_RENDER);

  <span class="com">// Compute orig and dir, used to draw a representation of the intersecting line
</span>  camera()-&gt;convertClickToLine(e-&gt;x(), e-&gt;y(), orig, dir);

  <span class="com">// Display of selection results
</span>  cout &lt;&lt; <span class="str">&quot;(&quot;</span> &lt;&lt; e-&gt;x() &lt;&lt; <span class="str">&quot;,&quot;</span> &lt;&lt; e-&gt;y() &lt;&lt; <span class="str">&quot;) : &quot;</span>;
  <span class="key">if </span>(nb_hits &lt;= <span class="num">0</span>)
    {
      selected = <span class="num">-1</span>;
      cout &lt;&lt; <span class="str">&quot;No object selected&quot;</span> &lt;&lt; endl;
      <span class="key">return</span>;
    }
  cout &lt;&lt; nb_hits &lt;&lt; <span class="str">&quot; spiral&quot;</span> &lt;&lt; ((nb_hits&gt;<span class="num">1</span>)?<span class="str">&quot;s&quot;</span>:<span class="str">&quot;&quot;</span>) &lt;&lt; <span class="str">&quot; under the cursor&quot;</span> &lt;&lt; endl;

  <span class="com">// Interpret results : each object created 4 values in the &quot;hits&quot; array :
</span>  <span class="com">// hits[4*i+1] is the object minimum depth value, while hits[4*i+3] is the id pushed on the stack.
</span>  <span class="com">// Of all the objects that were projected in the pick region, we select the closest one (zMin comparaison).
</span>  <span class="com">// This code needs to be modified if you use several stack levels. See glSelectBuffer() man page.
</span>  <span class="typ">unsigned int </span>zMin = hits[<span class="num">1</span>];
  selected = hits[<span class="num">3</span>];
  <span class="key">for </span>(<span class="typ">int </span>i=<span class="num">1</span>; i&lt;nb_hits; ++i)
    <span class="key">if </span>(hits[i*<span class="num">4</span>+<span class="num">1</span>] &lt; zMin)
      {
	zMin = hits[i*<span class="num">4</span>+<span class="num">1</span>];
	selected = hits[i*<span class="num">4</span>+<span class="num">3</span>];
      }

  <span class="com">// Find the selectedPoint coordinates, using camera()-&gt;pointUnderPixel().
</span>  <span class="typ">bool </span>found;
  selectedPoint = camera()-&gt;pointUnderPixel(e-&gt;x(), e-&gt;y(), found);
  selectedPoint -= <span class="num">0.01</span>*dir; <span class="com">// Small offset to make point clearly visible.
</span>  <span class="com">// Note that &quot;found&quot; is different from (selected&gt;=0) because of SENSITIVITY.
</span>}

<span class="typ">void </span>Viewer::init()
{
  restoreFromFile();

  <span class="com">// Means no object is selected.
</span>  selected = <span class="num">-1</span>;

  glLineWidth(<span class="num">3.0</span>);
  glPointSize(<span class="num">10.0</span>);

  help();
}

<span class="typ">void </span>Viewer::draw()
{
  drawScene();

  <span class="com">// Draw the previous intersection line
</span>  glBegin(GL_LINES);
  glVertex3fv(orig.address());
  glVertex3fv((orig + <span class="num">100.0</span>*dir).address());
  glEnd();

  <span class="key">if </span>(selected &gt;= <span class="num">0</span>)
    {
      glColor3f(.<span class="num">9</span>, .<span class="num">2</span>, .<span class="num">1</span>);
      glBegin(GL_POINTS);
      glVertex3fv(selectedPoint.address());
      glEnd();
    }
}

QString Viewer::helpString() <span class="typ">const
</span>{
  QString text(<span class="str">&quot;&lt;h2&gt;S e l e c t&lt;/h2&gt;&quot;</span>);
  text += <span class="str">&quot;Left click while pressing the &lt;b&gt;Shift&lt;/b&gt; key to select an object of the scene.&lt;br&gt;&quot;</span>;
  text += <span class="str">&quot;Selection is performed using the OpenGL &lt;i&gt;GL_SELECT&lt;/i&gt; render mode. &quot;</span>;
  text += <span class="str">&quot;A line is drawn between the selected point and the camera selection position. &quot;</span>;
  text += <span class="str">&quot;using &lt;i&gt;convertClickToLine()&lt;/i&gt;, a useful function for analytical intersections.&lt;br&gt;&quot;</span>;
  text += <span class="str">&quot;Feel free to cut and paste this implementation in your own applications.&quot;</span>;
  <span class="key">return </span>text;
}</pre>


<h2>main.cpp</h2>
<pre>

<span class="dir">#include </span><span class="dstr">&quot;select.h&quot;</span><span class="dir">
</span><span class="dir">#include &lt;qapplication.h&gt;
</span>
<span class="typ">int </span>main(<span class="typ">int </span>argc, <span class="typ">char</span>** argv)
{
  <span class="com">// Read command lines arguments.
</span>  QApplication application(argc,argv);

  <span class="com">// Instantiate the viewer.
</span>  Viewer v;

  <span class="com">// Make the viewer window visible on screen.
</span>  v.show();

  <span class="com">// Set the viewer as the application main widget.
</span>  application.setMainWidget(&amp;v);

  <span class="com">// Run main loop.
</span>  <span class="key">return </span>application.exec();
}</pre>



<p>
  <a href="index.html">Go back</a> to the examples main page
</p>

<p>
  <a href="http://validator.w3.org/check/referer"><img src="../images/xhtml.png" alt="Valid XHTML 1.0!" height="31" width="88" border="0"/></a>
  <a href="http://jigsaw.w3.org/css-validator/check/referer"><img src="../images/css.png" width="88" height="31" alt="Valid CSS!" border="0"/></a>
<i>Last modified on Thursday, February 5, 2004.</i>
</p>

</body>
</html>