2007-05-15 16:57:34 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* VCGLib o o *
|
|
|
|
* Visual and Computer Graphics Library o o *
|
|
|
|
* _ O _ *
|
|
|
|
* Copyright(C) 2004 \/)\/ *
|
|
|
|
* Visual Computing Lab /\/| *
|
|
|
|
* ISTI - Italian National Research Council | *
|
|
|
|
* \ *
|
|
|
|
* All rights reserved. *
|
|
|
|
* *
|
2007-07-14 14:44:40 +02:00
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
2007-05-15 16:57:34 +02:00
|
|
|
* 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. *
|
|
|
|
* *
|
|
|
|
* This program 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 (http://www.gnu.org/licenses/gpl.txt) *
|
|
|
|
* for more details. *
|
|
|
|
* *
|
|
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
|
|
History
|
|
|
|
|
|
|
|
$Log: not supported by cvs2svn $
|
2008-02-26 19:55:55 +01:00
|
|
|
Revision 1.13 2008/02/26 18:46:55 ponchio
|
|
|
|
Fixed bug in drawing position of the trackball when changin center.
|
|
|
|
|
2008-02-26 19:46:55 +01:00
|
|
|
Revision 1.12 2008/02/24 18:10:54 ponchio
|
|
|
|
Fixed scale behaviour.
|
|
|
|
|
2008-02-24 19:10:54 +01:00
|
|
|
Revision 1.11 2008/02/24 18:05:08 ponchio
|
|
|
|
Should work as before. I didn't test cylinder and other exotic modes.
|
|
|
|
|
2008-02-24 19:05:08 +01:00
|
|
|
Revision 1.10 2008/02/24 14:37:00 ponchio
|
|
|
|
Restored trackball functionality. Not very much tested, and code will need some
|
|
|
|
cleanup.
|
|
|
|
|
2008-02-24 15:37:00 +01:00
|
|
|
Revision 1.9 2008/02/22 18:57:47 benedetti
|
|
|
|
first attempt to correct after quaternion ToMatrix() inversion (does not work yet)
|
|
|
|
|
2008-02-22 19:57:47 +01:00
|
|
|
Revision 1.8 2008/02/15 20:54:45 benedetti
|
|
|
|
removed some variable initialization related warning
|
|
|
|
|
2008-02-15 21:54:45 +01:00
|
|
|
Revision 1.7 2007/10/22 14:39:54 cignoni
|
|
|
|
corrected bug into the drawsphere (thanks to nico and guido!)
|
|
|
|
|
2007-10-22 16:39:54 +02:00
|
|
|
Revision 1.6 2007/08/17 09:19:40 cignoni
|
|
|
|
glEnable (GL_LINE_SMOOTH) should go before changing the linewidth.
|
|
|
|
|
2007-08-17 11:19:40 +02:00
|
|
|
Revision 1.5 2007/07/14 12:44:40 benedetti
|
|
|
|
Minor edits in Doxygen documentation.
|
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
Revision 1.4 2007/07/09 22:41:22 benedetti
|
|
|
|
Added Doxygen documentation, removed using namespace std, some other minor changes.
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
Revision 1.3 2007/06/12 08:58:08 benedetti
|
|
|
|
Minor fix in DrawUglyCylinderMode()
|
|
|
|
|
2007-06-12 10:58:08 +02:00
|
|
|
Revision 1.2 2007/05/28 08:10:47 fiorin
|
|
|
|
Removed type cast warnings
|
|
|
|
|
2007-05-28 10:10:47 +02:00
|
|
|
Revision 1.1 2007/05/15 14:57:34 benedetti
|
|
|
|
Utility functions for the trackmodes, first version
|
|
|
|
|
2007-05-15 16:57:34 +02:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef TRACKUTILS_H
|
|
|
|
#define TRACKUTILS_H
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <vcg/math/base.h>
|
|
|
|
#include <vcg/math/similarity.h>
|
|
|
|
#include <vcg/space/intersection3.h>
|
|
|
|
#include <vcg/space/line3.h>
|
|
|
|
#include <vcg/space/plane3.h>
|
|
|
|
#include <wrap/gl/math.h>
|
|
|
|
#include <wrap/gl/space.h>
|
|
|
|
#include <vector>
|
2008-02-24 15:37:00 +01:00
|
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
2007-05-15 16:57:34 +02:00
|
|
|
|
|
|
|
namespace vcg {
|
2007-07-10 00:41:22 +02:00
|
|
|
|
|
|
|
/*!
|
2007-07-14 14:44:40 +02:00
|
|
|
@brief This namespace contains some support functions used by TrackMode subclassess.
|
2007-07-10 00:41:22 +02:00
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
\warning Many of these functions shouldn't be here and are supposed to be moved to some appropriate place by the library administrator.
|
|
|
|
\warning The \e DrawUgly series of functions is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
2007-07-10 00:41:22 +02:00
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
namespace trackutils {
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Compute the plane perpedicular to view dir and passing through the manipulator center.
|
|
|
|
|
|
|
|
@param camera the camera of the manipulator.
|
|
|
|
@param center the center of the manipulator.
|
|
|
|
@return the plane perpedicular to view dir and passing through the manipulator center.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
Plane3f GetViewPlane (const View < float >&camera, const Point3f & center)
|
|
|
|
{
|
|
|
|
Point3f vp = camera.ViewPoint ();
|
|
|
|
Plane3f pl;
|
|
|
|
Point3f plnorm = vp - center;
|
2008-10-27 20:35:17 +01:00
|
|
|
plnorm.Normalize();
|
|
|
|
pl.Set(plnorm, plnorm.dot(center));
|
2007-05-15 16:57:34 +02:00
|
|
|
return pl;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Convert a line to a normalized ray.
|
|
|
|
|
|
|
|
@param l the line to be converted.
|
|
|
|
@return the normalized ray.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
Ray3f line2ray(const Line3f &l){
|
|
|
|
Ray3f r(l.Origin(),l.Direction());
|
|
|
|
r.Normalize();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
|
|
|
|
/*!
|
|
|
|
@brief Project a window coordinate point on the plane perpedicular to view dir and passing through the manipulator center.
|
|
|
|
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param p the window coordinate point.
|
|
|
|
@return p's projection on plane perpedicular to view dir and passing through the manipulator center.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f HitViewPlane (Trackball * tb, const Point3f & p)
|
|
|
|
{
|
|
|
|
Plane3f vp = GetViewPlane (tb->camera, tb->center);
|
|
|
|
Line3fN ln = tb->camera.ViewLineFromWindow (Point3f (p[0], p[1], 0));
|
|
|
|
Point3f PonVP;
|
2012-01-18 17:49:18 +01:00
|
|
|
IntersectionPlaneLine < float >(vp, ln, PonVP);
|
2007-05-15 16:57:34 +02:00
|
|
|
return PonVP;
|
|
|
|
}
|
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
// nota: non ho scritto io questa funzione,
|
|
|
|
// quindi la documentazione doxy potrebbe non essere accurata al 100%.
|
|
|
|
/*!
|
|
|
|
@brief Project a window coordinate point on the rotational hyperboloid relative to the manipulator.
|
2007-07-10 00:41:22 +02:00
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
<br>The original documentation (in italian) follows:
|
|
|
|
<pre>
|
2007-05-15 16:57:34 +02:00
|
|
|
dato un punto in coordinate di schermo e.g. in pixel stile opengl
|
2007-07-14 14:44:40 +02:00
|
|
|
calcola il punto di intersezione tra la viewline che passa per
|
|
|
|
viewpoint e per hitplane e l'iperboloide.
|
|
|
|
l'iperboloide si assume essere quello di rotazione attorno alla
|
|
|
|
retta viewpoint-center e di raggio rad
|
|
|
|
si assume come sistema di riferimento quello con l'origine
|
|
|
|
su center ecome x la retta center-viewpoint
|
2007-05-15 16:57:34 +02:00
|
|
|
|
|
|
|
eq linea
|
|
|
|
hitplane.y
|
|
|
|
y = - ----------- * x + hitplane.y
|
|
|
|
viewpoint.x
|
|
|
|
|
|
|
|
eq hiperboloide di raggio r (e.g. che passa per (r/sqrt2,r/sqrt2)
|
|
|
|
|
|
|
|
1
|
|
|
|
y = --- * (r^2 /2.0)
|
|
|
|
x
|
|
|
|
|
|
|
|
hitplane.y
|
|
|
|
----------- * x^2 - hitplane.y *x + (r^2/2.0) == 0
|
|
|
|
viewpoint.x
|
2007-07-14 14:44:40 +02:00
|
|
|
</pre>
|
2007-07-10 00:41:22 +02:00
|
|
|
|
|
|
|
@param center the center of the manipulator.
|
|
|
|
@param radius the radius of the manipulator.
|
|
|
|
@param viewpoint the view point.
|
|
|
|
@param vp the view plane.
|
|
|
|
@param hitplane the projection of the window coordinate point on the view plane.
|
|
|
|
@param hit the projection of hitplane on the rotational hyperboloid relative to the manipulator.
|
|
|
|
@return true if and only if hit is valid.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
bool HitHyper (Point3f center, float radius, Point3f viewpoint, Plane3f vp,
|
|
|
|
Point3f hitplane, Point3f & hit)
|
|
|
|
{
|
|
|
|
float hitplaney = Distance (center, hitplane);
|
|
|
|
float viewpointx = Distance (center, viewpoint);
|
|
|
|
|
|
|
|
float a = hitplaney / viewpointx;
|
|
|
|
float b = -hitplaney;
|
|
|
|
float c = radius * radius / 2.0f;
|
|
|
|
float delta = b * b - 4 * a * c;
|
|
|
|
float x1, x2, xval, yval;
|
|
|
|
|
|
|
|
if (delta > 0) {
|
|
|
|
x1 = (-b - sqrt (delta)) / (2.0f * a);
|
|
|
|
x2 = (-b + sqrt (delta)) / (2.0f * a);
|
|
|
|
|
|
|
|
xval = x1; // always take the minimum value solution
|
|
|
|
yval = c / xval; // alternatively it also could be the other part of the equation yval=-(hitplaney/viewpointx)*xval+hitplaney;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Computing the result in 3d space;
|
|
|
|
Point3f dirRadial = hitplane - center;
|
|
|
|
dirRadial.Normalize ();
|
|
|
|
Point3f dirView = vp.Direction ();
|
|
|
|
dirView.Normalize ();
|
|
|
|
hit = center + dirRadial * yval + dirView * xval;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
// nota: non ho scritto io questa funzione,
|
|
|
|
// quindi la documentazione doxy potrebbe non essere accurata al 100%.
|
|
|
|
/*!
|
|
|
|
@brief Project a window coordinate point on the sphere relative to the manipulator.
|
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
<br>The original documentation (in italian) follows:
|
|
|
|
<pre>
|
|
|
|
dato un punto in coordinate di schermo e.g. in pixel stile opengl
|
|
|
|
restituisce un punto in coordinate di mondo sulla superficie
|
|
|
|
della trackball.
|
|
|
|
La superficie della trackball e' data da una sfera + una porzione
|
|
|
|
di iperboloide di rotazione.
|
|
|
|
Assumiamo la sfera di raggio unitario e centrata sull'origine e
|
|
|
|
di guardare lungo la y negativa.
|
|
|
|
|
|
|
|
X 0 sqrt(1/2) 1
|
|
|
|
eq sfera: y=sqrt(1-x*x); 1 sqrt(1/2) 0
|
|
|
|
eq iperboloide : y=1/2*x; inf sqrt(1/2) 1/2
|
|
|
|
eq cono y=x+sqrt(2);
|
|
|
|
</pre>
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
@param tb the manipulator.
|
|
|
|
@param p the window coordinate point.
|
|
|
|
@return the projection of p on the sphere relative to the manipulator.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f HitSphere (Trackball * tb, const Point3f & p)
|
|
|
|
{
|
2008-02-24 19:05:08 +01:00
|
|
|
Point3f center = tb->center;
|
2008-02-24 15:37:00 +01:00
|
|
|
Line3fN ln = tb->camera.ViewLineFromWindow (Point3f (p[0], p[1], 0));
|
|
|
|
Plane3f vp = GetViewPlane (tb->camera, center);
|
|
|
|
Point3f hitPlane(0,0,0), //intersection view plane with point touched
|
|
|
|
hitSphere(0,0,0),
|
|
|
|
hitSphere1(0,0,0),
|
|
|
|
hitSphere2(0,0,0),
|
|
|
|
hitHyper(0,0,0);
|
2012-01-18 17:49:18 +01:00
|
|
|
IntersectionPlaneLine < float >(vp, ln, hitPlane);
|
2008-02-24 15:37:00 +01:00
|
|
|
|
|
|
|
Sphere3f sphere (center, tb->radius);//trackball sphere
|
2007-05-15 16:57:34 +02:00
|
|
|
bool resSp = IntersectionLineSphere < float >(sphere, ln, hitSphere1, hitSphere2);
|
|
|
|
|
2008-02-24 15:37:00 +01:00
|
|
|
Point3f viewpoint = tb->camera.ViewPoint ();
|
2007-05-15 16:57:34 +02:00
|
|
|
if (resSp == true) {
|
|
|
|
if (Distance (viewpoint, hitSphere1) < Distance (viewpoint, hitSphere2))
|
|
|
|
hitSphere = hitSphere1;
|
|
|
|
else
|
|
|
|
hitSphere = hitSphere2;
|
|
|
|
}
|
|
|
|
|
2008-02-24 15:37:00 +01:00
|
|
|
/*float dl= */ Distance (ln, center);
|
|
|
|
bool resHp = HitHyper (center, tb->radius, viewpoint, vp, hitPlane, hitHyper);
|
2007-05-15 16:57:34 +02:00
|
|
|
|
|
|
|
// four cases
|
|
|
|
|
|
|
|
// 1) Degenerate line tangent to both sphere and hyperboloid!
|
|
|
|
if ((!resSp && !resHp)) {
|
2008-02-24 15:37:00 +01:00
|
|
|
Point3f hit = ClosestPoint (ln, center);
|
2007-05-15 16:57:34 +02:00
|
|
|
//printf("closest point to line %f\n",Distance(hit,tb->center));
|
|
|
|
return hit;
|
|
|
|
}
|
|
|
|
if ((resSp && !resHp))
|
|
|
|
return hitSphere; // 2) line cross only the sphere
|
|
|
|
if ((!resSp && resHp))
|
|
|
|
return hitHyper; // 3) line cross only the hyperboloid
|
|
|
|
|
|
|
|
// 4) line cross both sphere and hyperboloid: choose according angle.
|
2008-02-24 15:37:00 +01:00
|
|
|
float angleDeg = math::ToDeg (Angle ((viewpoint - center), (hitSphere - center)));
|
2007-05-15 16:57:34 +02:00
|
|
|
|
|
|
|
//printf("Angle %f (%5.2f %5.2f %5.2f) (%5.2f %5.2f %5.2f)\n",angleDeg,hitSphere[0],hitSphere[1],hitSphere[2],hitHyper[0],hitHyper[1],hitHyper[2]);
|
|
|
|
if (angleDeg < 45)
|
|
|
|
return hitSphere;
|
|
|
|
else
|
|
|
|
return hitHyper;
|
|
|
|
|
|
|
|
// Codice ORIGINALE PONCHIO
|
|
|
|
//vp.SetOffset(vp.Offset() + Thr);
|
|
|
|
|
|
|
|
//Point3f hit;
|
|
|
|
//bool res = Intersection<float>(vp, ln, hit);
|
|
|
|
//float d = Distance(tb->center - vn.Direction()*Thr, hit);
|
|
|
|
//if(d < Thr) {
|
|
|
|
// Point3f hit2;
|
|
|
|
// Sphere3f sphere(tb->center, tb->radius);
|
|
|
|
// bool res = Intersection<float>(sphere, ln, hit, hit2);
|
|
|
|
|
|
|
|
// //find closest intersection to sphere
|
|
|
|
// float d = (hit - viewpoint).Norm();
|
|
|
|
// float d2 = (hit2 - viewpoint).Norm();
|
|
|
|
// if(d > d2) hit = hit2;
|
|
|
|
// hit -= tb->center;
|
|
|
|
//} else {
|
|
|
|
// if(d > 2.99 * Thr)
|
|
|
|
// d = 2.99 * Thr;
|
|
|
|
// Point3f norm = (hit - tb->center)^(viewpoint - tb->center);
|
|
|
|
// norm.Normalize();
|
|
|
|
// float phi = -M_PI/4 - 3*M_PI/8 *(d - Thr)/Thr;
|
|
|
|
|
|
|
|
// Quaternionf q(phi, norm);
|
|
|
|
// hit = q.Rotate((viewpoint - tb->center).Normalize() * tb->radius);
|
|
|
|
//}
|
|
|
|
// hit.Normalize();
|
|
|
|
// return hit;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Calculates the minimal distance between 2 lines.
|
|
|
|
|
|
|
|
P and Q are the lines, P_s and Q_t are set to be the closest points on these lines.
|
|
|
|
|
|
|
|
it's returned the distance from P_s and Q_t, and a boolean value which is true
|
|
|
|
if the lines are parallel enough.
|
|
|
|
|
|
|
|
if P and Q are parallel P_s and Q_t aren't set.
|
|
|
|
|
|
|
|
the formula is taken from pages 81-83 of
|
|
|
|
<em>"Eric Lengyel - Mathematics for 3D Game Programming & Computer Graphics"</em>
|
|
|
|
@param P the first line.
|
|
|
|
@param Q the second line.
|
|
|
|
@param P_s the point on P closest to Q.
|
|
|
|
@param Q_t the point on Q closest to P.
|
|
|
|
@return a std::pair made with the distance from P_s to Q_t and a boolean value, true if and only if P and Q are almost parallel.
|
2007-05-15 16:57:34 +02:00
|
|
|
*/
|
2007-07-10 00:41:22 +02:00
|
|
|
std::pair< float, bool > LineLineDistance(const Line3f & P,const Line3f & Q,Point3f & P_s, Point3f & Q_t){
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f p0 = P.Origin (), Vp = P.Direction ();
|
|
|
|
Point3f q0 = Q.Origin (), Vq = Q.Direction ();
|
2008-10-27 20:35:17 +01:00
|
|
|
float VPVP = Vp.dot(Vp);
|
|
|
|
float VQVQ = Vq.dot(Vq);
|
|
|
|
float VPVQ = Vp.dot(Vq);
|
2007-05-15 16:57:34 +02:00
|
|
|
const float det = ( VPVP * VQVQ ) - ( VPVQ * VPVQ );
|
|
|
|
const float EPSILON = 0.00001f;
|
|
|
|
if ( fabs(det) < EPSILON ) {
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(Distance(P,q0), true);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
2008-10-27 20:35:17 +01:00
|
|
|
float b1= (q0 - p0).dot(Vp);
|
|
|
|
float b2= (p0 - q0).dot(Vq);
|
2007-05-15 16:57:34 +02:00
|
|
|
float s = ( (VQVQ * b1) + (VPVQ * b2) ) / det;
|
|
|
|
float t = ( (VPVQ * b1) + (VPVP * b2) ) / det;
|
|
|
|
P_s = p0 + (Vp * s);
|
|
|
|
Q_t = q0 + (Vq * t);
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(Distance(P_s,Q_t),false);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Calculates the minimal distance between a ray and a line.
|
|
|
|
|
|
|
|
R is the ray and Q is the line, R_s and Q_t are set to be the closest points on
|
|
|
|
the ray and the line.
|
|
|
|
|
|
|
|
it's returned the distance from R_s and Q_t, and a boolean value which is true
|
|
|
|
if the ray and the line are parallel enough.
|
|
|
|
|
|
|
|
if R and Q are parallel R_s and Q_t aren't set.
|
|
|
|
@param R the ray.
|
|
|
|
@param Q the line.
|
|
|
|
@param R_s the point on R closest to Q.
|
|
|
|
@param Q_t the point on Q closest to R.
|
|
|
|
@return a std::pair made with the distance from R_s to Q_t and a boolean value, true if and only if P and Q are almost parallel.
|
2007-05-15 16:57:34 +02:00
|
|
|
*/
|
2007-07-10 00:41:22 +02:00
|
|
|
std::pair< float, bool > RayLineDistance(const Ray3f & R,const Line3f & Q,Point3f & R_s, Point3f & Q_t){
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f r0 = R.Origin (), Vr = R.Direction ();
|
|
|
|
Point3f q0 = Q.Origin (), Vq = Q.Direction ();
|
2008-10-27 20:35:17 +01:00
|
|
|
float VRVR = Vr.dot(Vr);
|
|
|
|
float VQVQ = Vq.dot(Vq);
|
|
|
|
float VRVQ = Vr.dot(Vq);
|
2007-05-15 16:57:34 +02:00
|
|
|
const float det = ( VRVR * VQVQ ) - ( VRVQ * VRVQ );
|
|
|
|
const float EPSILON = 0.00001f;
|
|
|
|
if ( ( det >= 0.0f ? det : -det) < EPSILON ) {
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(Distance(Q,r0), true);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
2008-10-27 20:35:17 +01:00
|
|
|
float b1= (q0 - r0).dot(Vr);
|
|
|
|
float b2= (r0 - q0).dot(Vq);
|
2007-05-15 16:57:34 +02:00
|
|
|
float s = ( (VQVQ * b1) + (VRVQ * b2) ) / det;
|
|
|
|
float t = ( (VRVQ * b1) + (VRVR * b2) ) / det;
|
|
|
|
if(s<0){
|
|
|
|
R_s = r0;
|
|
|
|
Q_t = ClosestPoint(Q,R_s);
|
|
|
|
}else {
|
|
|
|
R_s = r0 + (Vr * s);
|
|
|
|
Q_t = q0 + (Vq * t);
|
|
|
|
}
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(Distance(R_s,Q_t),false);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
2010-10-15 17:21:43 +02:00
|
|
|
///*!
|
|
|
|
// @brief Calculates the minimal distance between 2 segments.
|
|
|
|
//
|
|
|
|
// R e Q are the segments, R_s and Q_t are set to be the closest points on
|
|
|
|
// the segments.
|
|
|
|
//
|
|
|
|
// it's returned the distance from R_s and Q_t, and a boolean value which is true
|
|
|
|
// if the segments are parallel enough.
|
|
|
|
// @param R the first segment.
|
|
|
|
// @param Q the second segment.
|
|
|
|
// @param R_s the point on R closest to Q.
|
|
|
|
// @param Q_t the point on Q closest to R.
|
|
|
|
// @return a std::pair made with the distance from R_s to Q_t and a boolean value, true if and only if P and Q are almost parallel.
|
|
|
|
//*/
|
|
|
|
//std::pair< float, bool > SegmentSegmentDistance(const Segment3f & R, const Segment3f & Q, Point3f & R_s, Point3f & Q_t)
|
|
|
|
//{
|
|
|
|
// float R_len=Distance(R.P0(),R.P1());
|
|
|
|
// float Q_len=Distance(Q.P0(),Q.P1());
|
|
|
|
// const float EPSILON_LENGTH = std::max(R_len,Q_len)*0.0001f;
|
|
|
|
// if(R_len < EPSILON_LENGTH){
|
|
|
|
// R_s=R.P0();
|
|
|
|
// Q_t=ClosestPoint(Q,R_s);
|
|
|
|
// return std::make_pair(Distance(R_s,Q_t),true);
|
|
|
|
// }
|
|
|
|
// if( Q_len < EPSILON_LENGTH){
|
|
|
|
// Q_t=Q.P0();
|
|
|
|
// R_s=ClosestPoint(R,Q_t);
|
|
|
|
// return std::make_pair(Distance(R_s,Q_t),true);
|
|
|
|
// }
|
|
|
|
// Point3f r0 = R.P0(), Vr = (R.P1()-R.P0()).normalized();
|
|
|
|
// Point3f q0 = Q.P0(), Vq = (Q.P1()-Q.P0()).normalized();
|
|
|
|
// float VRVR = Vr.dot(Vr);
|
|
|
|
// float VQVQ = Vq.dot(Vq);
|
|
|
|
// float VRVQ = Vr.dot(Vq);
|
|
|
|
// const float det = ( VRVR * VQVQ ) - ( VRVQ * VRVQ );
|
|
|
|
// const float EPSILON = 0.00001f;
|
|
|
|
// if ( ( det >= 0.0f ? det : -det) < EPSILON ) {
|
|
|
|
// Line3f lR(R.P0(),R.P1());
|
|
|
|
// float qa=lR.Projection(Q.P0());
|
|
|
|
// float qb=lR.Projection(Q.P1());
|
|
|
|
// if( (qa<=0.0f) && qb<=(0.0f)){
|
|
|
|
// R_s=R.P0();
|
|
|
|
// Q_t=ClosestPoint(Q,R_s);
|
|
|
|
// } else if ( (qa >= 1.0f) && (qb >= 1.0f) ){
|
|
|
|
// R_s=R.P1();
|
|
|
|
// Q_t=ClosestPoint(Q,R_s);
|
|
|
|
// } else {
|
|
|
|
// if( (qa >= 0.0f) && (qa <= 1.0f) ){
|
|
|
|
// Q_t=Q.P0();
|
|
|
|
// R_s=ClosestPoint(R,Q_t);
|
|
|
|
// } else if((qb >= 0.0f) && (qb <= 1.0f) ){
|
|
|
|
// Q_t=Q.P1();
|
|
|
|
// R_s=ClosestPoint(R,Q_t);
|
|
|
|
// } else {
|
|
|
|
// if( ( ((qa<=0.0f)&&(qb>=1.0f)) || (((qb<=0.0f)&&(qa>=1.0f))))){
|
|
|
|
// R_s=R.P0();
|
|
|
|
// Q_t=ClosestPoint(Q,R_s);
|
|
|
|
// }else{
|
|
|
|
// assert(0);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return std::make_pair(Distance(R_s,Q_t),true);
|
|
|
|
// }
|
|
|
|
// float b1= (q0 - r0).dot(Vr);
|
|
|
|
// float b2= (r0 - q0).dot(Vq);
|
|
|
|
// float s = ( (VQVQ * b1) + (VRVQ * b2) ) / det;
|
|
|
|
// float t = ( (VRVQ * b1) + (VRVR * b2) ) / det;
|
|
|
|
// if( s < 0 ){
|
|
|
|
// R_s = R.P0();
|
|
|
|
// }else if ( s > R_len ){
|
|
|
|
// R_s = R.P1();
|
|
|
|
// } else {
|
|
|
|
// R_s = r0 + (Vr * s);
|
|
|
|
// }
|
|
|
|
// if( t < 0){
|
|
|
|
// Q_t = Q.P0();
|
|
|
|
// }else if ( t > Q_len ){
|
|
|
|
// Q_t = Q.P1();
|
|
|
|
// }else{
|
|
|
|
// Q_t = q0 + (Vq * t);
|
|
|
|
// }
|
|
|
|
// return std::make_pair(Distance(R_s,Q_t),false);
|
|
|
|
//}
|
2007-05-15 16:57:34 +02:00
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Compute the point on a line closest to the ray projection of a window coordinate point.
|
|
|
|
|
|
|
|
Given a window coordinate point, computes a ray starting from the manipulator
|
|
|
|
camera eye and passing through the point's projection on the viewplane, then uses RayLineDistance()
|
|
|
|
to get the closest point to ray on a given line.
|
|
|
|
@see RayLineDistance(const Ray3f & R,const Line3f & Q,Point3f & R_s, Point3f & Q_t)
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param axis the axis.
|
|
|
|
@param point the window coordinate point.
|
|
|
|
@return a std::pair made with the point on axis closest to the ray projection of point and a boolean true if and only if the ray doesn't diverges respect to the axis.
|
|
|
|
*/
|
|
|
|
std::pair< Point3f,bool > HitNearestPointOnAxis (Trackball * tb,Line3f axis, Point3f point)
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
|
|
|
Ray3fN ray = line2ray(tb->camera.ViewLineFromWindow (point));
|
|
|
|
Point3f axis_p(0,0,0), ray_p(0,0,0);
|
2007-07-10 00:41:22 +02:00
|
|
|
std::pair< float, bool > resp=RayLineDistance(ray,axis,ray_p,axis_p);
|
2007-05-15 16:57:34 +02:00
|
|
|
if(resp.second || (ray_p == ray.Origin())){
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(Point3f(0,0,0),false);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(axis_p,true);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Project a line into a plane.
|
|
|
|
|
|
|
|
Given a line and a plane, returns the line projection on the plane.
|
2007-05-15 16:57:34 +02:00
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
The line returned is \e not normalized.
|
|
|
|
@param ln the line.
|
|
|
|
@param pl the plane.
|
|
|
|
@return the (non normalized) line projected.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
Line3f ProjectLineOnPlane(const Line3f & ln, const Plane3f & pl)
|
|
|
|
{
|
|
|
|
Point3f l0=ln.Origin();
|
|
|
|
Point3f l1=l0+ln.Direction();
|
|
|
|
Point3f p1,p2;
|
|
|
|
p1=pl.Projection(l0);
|
|
|
|
p2=pl.Projection(l1);
|
|
|
|
Line3f res(p1,p2-p1);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Computes a signed line-point distance.
|
|
|
|
|
|
|
|
Given a line, a point and a positivity direction, computes the signed distance between the line and the point.
|
|
|
|
@param line the line.
|
|
|
|
@param pt the point.
|
|
|
|
@param positive_dir the positivity direction.
|
|
|
|
@return the signed distance.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
float signedDistance(Line3f line,Point3f pt,Point3f positive_dir)
|
|
|
|
{
|
2008-10-27 20:35:17 +01:00
|
|
|
return Distance(line,pt) * ((((pt-ClosestPoint(line,pt)).dot(positive_dir)) >= 0.0f )? 1.0f: -1.0f);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
/*!
|
|
|
|
@brief Computes the verical component of an user mouse drag.
|
|
|
|
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param new_point the new mouse pointer coordinate.
|
|
|
|
@return The verical component of the user mouse drag.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
float getDeltaY(Trackball * tb, Point3f new_point)
|
|
|
|
{
|
|
|
|
float ScreenHeight = float (tb->camera.viewport[3] - tb->camera.viewport[1]);
|
|
|
|
return (new_point[1] - tb->last_point[1]) / ScreenHeight;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Computes the intersection between a ray and a plane.
|
|
|
|
|
|
|
|
@param pl the plane.
|
|
|
|
@param ray the ray.
|
|
|
|
@param po the intersection point.
|
|
|
|
@return true if and only if there is intersection (po is valid).
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
template<class T>
|
|
|
|
inline bool IntersectionRayPlane( const Plane3<T> & pl, const Ray3<T> & ray, Point3<T> &po){
|
|
|
|
const T epsilon = T(1e-8);
|
|
|
|
|
2008-10-27 20:35:17 +01:00
|
|
|
T k = pl.Direction().dot(ray.Direction()); // Compute 'k' factor
|
2007-05-15 16:57:34 +02:00
|
|
|
if( (k > -epsilon) && (k < epsilon))
|
|
|
|
return false;
|
2008-10-27 20:35:17 +01:00
|
|
|
T r = (pl.Offset() - pl.Direction().dot(ray.Origin()))/k; // Compute ray distance
|
2007-05-15 16:57:34 +02:00
|
|
|
if (r < 0)
|
|
|
|
return false;
|
|
|
|
po = ray.Origin() + ray.Direction()*r;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Project a window coordinate point on a plane.
|
|
|
|
|
|
|
|
Given a window coordinate point, computes a ray starting from the manipulator
|
|
|
|
camera eye and passing through the point's projection on the viewplane, then uses IntersectionRayPlane()
|
|
|
|
to get the ray intersection with a given plane.
|
|
|
|
|
2007-07-14 14:44:40 +02:00
|
|
|
@see IntersectionRayPlane()
|
2007-07-10 00:41:22 +02:00
|
|
|
@param tb the manipulator.
|
|
|
|
@param point the window coordinate point.
|
|
|
|
@param plane the plane.
|
|
|
|
@return a std::pair made with p's projection on the.plane and a boolean true if and only if the ray doesn't diverges respect to the plane.
|
|
|
|
*/
|
|
|
|
std::pair< Point3f, bool > HitPlane (Trackball * tb, Point3f point, Plane3f plane)
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
|
|
|
Ray3fN ray = line2ray(tb->camera.ViewLineFromWindow (point));
|
|
|
|
Point3f p(0,0,0);
|
|
|
|
bool res = IntersectionRayPlane < float >(plane, ray, p);
|
2007-07-10 00:41:22 +02:00
|
|
|
return std::make_pair(p,res);
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// drawing section
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
// nota: non ho scritto io questa classe,
|
|
|
|
// quindi la documentazione doxy potrebbe non essere accurata al 100%.
|
|
|
|
/*!
|
|
|
|
@brief Drawing hints for manipulators
|
|
|
|
|
|
|
|
This class is an holder for drawing-related variables.
|
|
|
|
|
|
|
|
It's mainly used for SphereMode and InactiveMode drawings.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
class DrawingHint {
|
|
|
|
public:
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Drawing hints constructor
|
|
|
|
|
|
|
|
assign the drawing-related variables.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
DrawingHint () {
|
|
|
|
CircleStep = 64;
|
|
|
|
HideStill = false;
|
|
|
|
DrawTrack = false;
|
2011-12-20 13:27:30 +01:00
|
|
|
LineWidthStill = 0.9f;
|
|
|
|
LineWidthMoving = 1.8f;
|
2007-05-15 16:57:34 +02:00
|
|
|
color = Color4b::LightBlue;
|
|
|
|
}
|
2007-07-10 00:41:22 +02:00
|
|
|
/// The circles resolution.
|
2007-05-15 16:57:34 +02:00
|
|
|
int CircleStep;
|
2007-07-10 00:41:22 +02:00
|
|
|
/// currently not in use.
|
|
|
|
bool HideStill;
|
|
|
|
/// currently not in use.
|
|
|
|
bool DrawTrack;
|
|
|
|
/// circle color
|
2007-05-15 16:57:34 +02:00
|
|
|
Color4b color;
|
2007-07-10 00:41:22 +02:00
|
|
|
/// circle line width when inactive.
|
2007-05-15 16:57:34 +02:00
|
|
|
float LineWidthStill;
|
2007-07-10 00:41:22 +02:00
|
|
|
/// circle line width when active.
|
2007-05-15 16:57:34 +02:00
|
|
|
float LineWidthMoving;
|
|
|
|
};
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/// the drawing hint used by the manipulators
|
2007-05-15 16:57:34 +02:00
|
|
|
DrawingHint DH;
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
// nota: non ho scritto io questa funzione,
|
|
|
|
// quindi la documentazione doxy potrebbe non essere accurata al 100%.
|
|
|
|
/*!
|
|
|
|
@brief Draw 2 squares, used by DrawCircle().
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawPlaneHandle ()
|
|
|
|
{
|
|
|
|
float r = 1.0;
|
|
|
|
float dr = r / 10.0f;
|
|
|
|
|
|
|
|
glBegin (GL_LINE_STRIP);
|
|
|
|
glVertex3f (+r + dr, +r, 0.0);
|
|
|
|
glVertex3f (+r, +r + dr, 0.0);
|
|
|
|
glVertex3f (+r - dr, +r, 0.0);
|
|
|
|
glVertex3f (+r, +r - dr, 0.0);
|
|
|
|
glVertex3f (+r + dr, +r, 0.0);
|
|
|
|
glEnd ();
|
|
|
|
glBegin (GL_LINE_STRIP);
|
|
|
|
glVertex3f (-r + dr, -r, 0.0);
|
|
|
|
glVertex3f (-r, -r + dr, 0.0);
|
|
|
|
glVertex3f (-r - dr, -r, 0.0);
|
|
|
|
glVertex3f (-r, -r - dr, 0.0);
|
|
|
|
glVertex3f (-r + dr, -r, 0.0);
|
|
|
|
glEnd ();
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
// nota: non ho scritto io questa funzione,
|
|
|
|
// quindi la documentazione doxy potrebbe non essere accurata al 100%.
|
|
|
|
/*!
|
|
|
|
@brief Draw a circle with 2 squares, used by DrawSphereIcon().
|
|
|
|
*/
|
2011-12-20 13:27:30 +01:00
|
|
|
void DrawCircle (bool planehandle=true)
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
|
|
|
int nside = DH.CircleStep;
|
|
|
|
const double pi2 = 3.14159265 * 2.0;
|
|
|
|
glBegin (GL_LINE_LOOP);
|
|
|
|
for (double i = 0; i < nside; i++) {
|
|
|
|
glNormal3d (cos (i * pi2 / nside), sin (i * pi2 / nside), 0.0);
|
|
|
|
glVertex3d (cos (i * pi2 / nside), sin (i * pi2 / nside), 0.0);
|
|
|
|
}
|
|
|
|
glEnd ();
|
2011-12-20 13:27:30 +01:00
|
|
|
if(planehandle)
|
|
|
|
DrawPlaneHandle();
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Draw a spherical manipulator icon.
|
|
|
|
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param active boolean to be set to true if the icon is active.
|
|
|
|
*/
|
2011-12-20 13:27:30 +01:00
|
|
|
void DrawSphereIcon (Trackball * tb, bool active, bool planeshandle=false)
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
2012-03-06 12:52:00 +01:00
|
|
|
glPushAttrib(GL_TRANSFORM_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT);
|
2007-10-22 16:39:54 +02:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
2008-02-26 19:55:55 +01:00
|
|
|
glPushMatrix ();
|
2012-03-06 12:52:00 +01:00
|
|
|
glDepthMask(GL_FALSE);
|
2008-02-26 19:55:55 +01:00
|
|
|
|
2008-02-26 19:46:55 +01:00
|
|
|
Point3f center = tb->center + tb->track.InverseMatrix()*Point3f(0, 0, 0);
|
2008-02-24 19:05:08 +01:00
|
|
|
glTranslate(center);
|
2008-02-24 19:10:54 +01:00
|
|
|
glScale (tb->radius/tb->track.sca);
|
2007-05-15 16:57:34 +02:00
|
|
|
|
2011-12-20 13:27:30 +01:00
|
|
|
float amb[4] = { .35f, .35f, .35f, 1.0f };
|
2007-05-15 16:57:34 +02:00
|
|
|
float col[4] = { .5f, .5f, .8f, 1.0f };
|
2007-08-17 11:19:40 +02:00
|
|
|
glEnable (GL_LINE_SMOOTH);
|
2007-05-15 16:57:34 +02:00
|
|
|
if (active)
|
|
|
|
glLineWidth (DH.LineWidthMoving);
|
|
|
|
else
|
|
|
|
glLineWidth (DH.LineWidthStill);
|
2011-12-20 13:27:30 +01:00
|
|
|
glDisable(GL_COLOR_MATERIAL); // has to be disabled, it is used by wrapper to draw meshes, and prevent direct material setting, used here
|
|
|
|
|
2007-05-15 16:57:34 +02:00
|
|
|
glEnable (GL_LIGHTING);
|
|
|
|
glEnable (GL_LIGHT0);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glColor (DH.color);
|
|
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, amb);
|
2011-12-20 13:27:30 +01:00
|
|
|
|
|
|
|
col[0] = .40f; col[1] = .40f; col[2] = .85f;
|
2007-05-15 16:57:34 +02:00
|
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
2011-12-20 13:27:30 +01:00
|
|
|
DrawCircle(planeshandle);
|
|
|
|
|
|
|
|
glRotatef (90, 1, 0, 0);
|
|
|
|
col[0] = .40f; col[1] = .85f; col[2] = .40f;
|
|
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
|
|
|
DrawCircle(planeshandle);
|
|
|
|
|
|
|
|
glRotatef (90, 0, 1, 0);
|
|
|
|
col[0] = .85f; col[1] = .40f; col[2] = .40f;
|
|
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
|
|
|
DrawCircle(planeshandle);
|
2007-10-22 16:39:54 +02:00
|
|
|
|
|
|
|
glPopMatrix ();
|
|
|
|
glPopAttrib ();
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TEMPORARY drawing section
|
|
|
|
// Disclaimer: the following code is of VERY POOR quality
|
|
|
|
// feel free to delete and rewrite everything
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Support function for the \e DrawUgly series of functions
|
|
|
|
|
|
|
|
Prepare the OpenGL attributes.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
*/
|
|
|
|
void prepare_attrib()
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
|
|
|
float amb[4] = { .3f, .3f, .3f, 1.0f };
|
|
|
|
float col[4] = { .5f, .5f, .8f, 1.0f };
|
|
|
|
glEnable (GL_LIGHTING);
|
|
|
|
glEnable (GL_LIGHT0);
|
|
|
|
glEnable (GL_LINE_SMOOTH);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, amb);
|
|
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, col);
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief Support function for the \e DrawUgly series of functions.
|
|
|
|
|
|
|
|
Draw a coordinate vector, usually a letter, near the manipulator icon in a user readable oriantation.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param ugly_letter the coordinate vector.
|
|
|
|
*/
|
|
|
|
void DrawUglyLetter(Trackball * tb,std::vector<Point3f> ugly_letter)
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
|
|
|
Point3f center=tb->camera.Project(tb->center);
|
|
|
|
float offset=0;
|
2011-03-25 11:37:07 +01:00
|
|
|
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(1,0,0) * tb->radius))));
|
|
|
|
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(0,1,0) * tb->radius))));
|
|
|
|
offset=(std::max)(offset,Distance(center,tb->camera.Project(tb->center+(Point3f(0,0,1) * tb->radius))));
|
2007-05-15 16:57:34 +02:00
|
|
|
glPushMatrix();
|
|
|
|
glPushAttrib (GL_ALL_ATTRIB_BITS);
|
|
|
|
// go to world coords
|
|
|
|
glTranslate (tb->center);
|
|
|
|
glMultMatrix (tb->track.InverseMatrix ());
|
|
|
|
glTranslate (-tb->center);
|
2007-07-10 00:41:22 +02:00
|
|
|
prepare_attrib();
|
2007-05-15 16:57:34 +02:00
|
|
|
glColor3f(1,1,1);
|
|
|
|
glLineWidth(4.0);
|
|
|
|
|
|
|
|
glBegin(GL_LINE_STRIP);
|
|
|
|
for(unsigned int i=0;i<ugly_letter.size();i++){
|
|
|
|
glVertex(tb->camera.UnProject(center+(ugly_letter[i] * offset * 0.25)
|
|
|
|
+Point3f(-offset,-offset,0)));
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glPopAttrib ();
|
|
|
|
glPopMatrix();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief PanMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw a PanMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawUglyPanMode(Trackball * tb)
|
|
|
|
{
|
2007-07-10 00:41:22 +02:00
|
|
|
std::vector<Point3f> ugly_p;
|
2007-05-15 16:57:34 +02:00
|
|
|
ugly_p.push_back(Point3f(-1,-1,0));
|
|
|
|
ugly_p.push_back(Point3f(-1,1,0));
|
|
|
|
ugly_p.push_back(Point3f(1,1,0));
|
|
|
|
ugly_p.push_back(Point3f(1,0,0));
|
|
|
|
ugly_p.push_back(Point3f(-1,0,0));
|
|
|
|
|
|
|
|
DrawUglyLetter(tb,ugly_p);
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief ZMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw a ZMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawUglyZMode(Trackball * tb)
|
|
|
|
{
|
2007-07-10 00:41:22 +02:00
|
|
|
std::vector<Point3f> ugly_z;
|
2007-05-15 16:57:34 +02:00
|
|
|
ugly_z.push_back(Point3f(-1,1,0));
|
|
|
|
ugly_z.push_back(Point3f(1,1,0));
|
|
|
|
ugly_z.push_back(Point3f(-1,-1,0));
|
|
|
|
ugly_z.push_back(Point3f(1,-1,0));
|
|
|
|
DrawUglyLetter(tb,ugly_z);
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief ScaleMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw a ScaleMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawUglyScaleMode(Trackball * tb)
|
|
|
|
{
|
2007-07-10 00:41:22 +02:00
|
|
|
std::vector<Point3f> ugly_s;
|
2007-05-15 16:57:34 +02:00
|
|
|
ugly_s.push_back(Point3f(1,1,0));
|
|
|
|
ugly_s.push_back(Point3f(-1,1,0));
|
|
|
|
ugly_s.push_back(Point3f(-1,0,0));
|
|
|
|
ugly_s.push_back(Point3f(1,0,0));
|
|
|
|
ugly_s.push_back(Point3f(1,-1,0));
|
|
|
|
ugly_s.push_back(Point3f(-1,-1,0));
|
|
|
|
DrawUglyLetter(tb,ugly_s);
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief AxisMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw an AxisMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param axis AxisMode's axis.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawUglyAxisMode(Trackball * tb,Line3f axis)
|
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glPushAttrib (GL_ALL_ATTRIB_BITS);
|
|
|
|
// go to world coords
|
|
|
|
glTranslate (tb->center);
|
|
|
|
glMultMatrix (tb->track.InverseMatrix ());
|
|
|
|
glTranslate (-tb->center);
|
2007-07-10 00:41:22 +02:00
|
|
|
prepare_attrib();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.9f, 0.9f, 0.2f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glLineWidth(2.0);
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex(axis.Origin()+(axis.Direction()*100));
|
|
|
|
glVertex(axis.Origin()-(axis.Direction()*100));
|
|
|
|
glEnd();
|
|
|
|
glPointSize(8.0);
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.2f, 0.2f, 0.9f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(axis.Origin());
|
|
|
|
glEnd();
|
|
|
|
glPopAttrib ();
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief PlaneMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw a PlaneMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param plane PlaneMode's plane.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawUglyPlaneMode(Trackball * tb,Plane3f plane)
|
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glPushAttrib (GL_ALL_ATTRIB_BITS);
|
|
|
|
// go to world coords
|
|
|
|
glTranslate (tb->center);
|
|
|
|
glMultMatrix (tb->track.InverseMatrix ());
|
|
|
|
glTranslate (-tb->center);
|
2007-07-10 00:41:22 +02:00
|
|
|
prepare_attrib();
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f p0,d1,d2,norm;
|
|
|
|
norm=plane.Direction();
|
|
|
|
p0=plane.Projection(Point3f(0,0,0));
|
|
|
|
d1=Point3f(0,1,0);
|
|
|
|
if(norm == d1 || norm == -d1)
|
|
|
|
d1 = Point3f(1,0,0);
|
|
|
|
d2=plane.Projection(d1);
|
2008-10-27 20:35:17 +01:00
|
|
|
d1=(d2 - p0).normalized();
|
|
|
|
d2=(d1 ^ norm).normalized();
|
2007-05-15 16:57:34 +02:00
|
|
|
glLineWidth(3.0);
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.2f, 0.2f, 0.9f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex(p0);
|
|
|
|
glVertex(p0+norm);
|
|
|
|
glEnd();
|
|
|
|
glLineWidth(1.0);
|
2007-05-28 10:10:47 +02:00
|
|
|
for(float i=0.5f; i<100.0f; i+=0.7f){
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
for(int a=0;a<360;a+=10){
|
2007-05-28 10:10:47 +02:00
|
|
|
float f0=i*cosf((float(M_PI)*float(a))/180.0f);
|
|
|
|
float f1=i*sinf((float(M_PI)*float(a))/180.0f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glVertex(p0+(d1*f0)+(d2*f1));
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.9f, 0.9f, 0.2f);
|
|
|
|
glPointSize(8.0f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(p0);
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.7f, 0.7f, 0.0f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glPointSize(6.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(p0+norm);
|
|
|
|
glEnd();
|
|
|
|
glPopAttrib ();
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief CylinderMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw a CylinderMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param axis CylinderMode's axis.
|
|
|
|
*/
|
2007-05-15 16:57:34 +02:00
|
|
|
void DrawUglyCylinderMode(Trackball * tb,Line3f axis)
|
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glPushAttrib (GL_ALL_ATTRIB_BITS);
|
|
|
|
// go to world coords
|
|
|
|
glTranslate (tb->center);
|
|
|
|
glMultMatrix (tb->track.InverseMatrix ());
|
|
|
|
glTranslate (-tb->center);
|
2007-07-10 00:41:22 +02:00
|
|
|
prepare_attrib();
|
2007-05-15 16:57:34 +02:00
|
|
|
Plane3f plane;
|
|
|
|
plane.Init(axis.Origin(),axis.Direction());
|
|
|
|
Point3f p0,d1,d2,norm;
|
|
|
|
norm=plane.Direction();
|
|
|
|
p0=plane.Projection(Point3f(0,0,0));
|
|
|
|
d1=Point3f(0,1,0);
|
|
|
|
if(norm == d1 || norm == -d1)
|
|
|
|
d1 = Point3f(1,0,0);
|
|
|
|
d2=plane.Projection(d1);
|
2008-10-27 20:35:17 +01:00
|
|
|
d1=(d2 - p0).normalized();
|
|
|
|
d2=(d1 ^ norm).normalized();
|
2007-05-15 16:57:34 +02:00
|
|
|
glLineWidth(1.0);
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.2f, 0.2f, 0.9f);
|
2007-05-15 16:57:34 +02:00
|
|
|
for(int i=-100;i<100;i++){
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
for(int a=0;a<360;a+=10){
|
2007-05-28 10:10:47 +02:00
|
|
|
float f0=(tb->radius)*cosf((float(M_PI)*float(a))/180.0f);
|
|
|
|
float f1=(tb->radius)*sinf((float(M_PI)*float(a))/180.0f);
|
2007-06-12 10:58:08 +02:00
|
|
|
glVertex(axis.Origin()+p0+(norm*float(i))+(d1*f0)+(d2*f1));
|
2007-05-15 16:57:34 +02:00
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
glLineWidth(3.0);
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.2f, 0.2f, 0.9f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex(axis.Origin());
|
|
|
|
glVertex(axis.Origin()+(axis.Direction()*100));
|
|
|
|
glEnd();
|
|
|
|
glLineWidth(1.5);
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.9f, 0.2f, 0.9f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex(axis.Origin());
|
|
|
|
glVertex(axis.Origin()-(axis.Direction()*100));
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.9f, 0.9f, 0.2f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glPointSize(8.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(axis.Origin());
|
|
|
|
glEnd();
|
|
|
|
glPopAttrib ();
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief PathMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw a PathMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param points PathMode's points.
|
|
|
|
@param current_point PathMode's current point.
|
|
|
|
@param prev_point PathMode's prev point.
|
|
|
|
@param next_point PathMode's next point.
|
|
|
|
@param old_hitpoint PathMode's old hitpoint.
|
|
|
|
@param wrap PathMode's wrap.
|
|
|
|
*/
|
|
|
|
void DrawUglyPathMode(Trackball * tb,const std::vector < Point3f > &points,
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f current_point,Point3f prev_point,
|
|
|
|
Point3f next_point,Point3f old_hitpoint,bool wrap)
|
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glPushAttrib (GL_ALL_ATTRIB_BITS);
|
|
|
|
// go to world coords
|
|
|
|
glTranslate (tb->center);
|
|
|
|
glMultMatrix (tb->track.InverseMatrix ());
|
|
|
|
glTranslate (-tb->center);
|
2007-07-10 00:41:22 +02:00
|
|
|
prepare_attrib();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.9f, 0.9f, 0.2f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glLineWidth(2.0);
|
|
|
|
if(wrap)
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
else
|
|
|
|
glBegin(GL_LINE_STRIP);
|
2007-07-10 00:41:22 +02:00
|
|
|
for (std::vector < Point3f >::const_iterator i = points.begin (); i != points.end (); ++i){
|
2007-05-15 16:57:34 +02:00
|
|
|
glVertex(*i);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glColor3f(1,0,1);
|
|
|
|
glPointSize(8.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(current_point);
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.6f, 0.0f, 0.6f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glPointSize(7.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(old_hitpoint);
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.7f, 0.7f, 0.7f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glPointSize(6.5);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(prev_point);
|
|
|
|
glVertex(next_point);
|
|
|
|
glEnd();
|
|
|
|
glPopAttrib ();
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
2007-07-10 00:41:22 +02:00
|
|
|
/*!
|
|
|
|
@brief AreaMode drawing function, member of the \e DrawUgly series.
|
|
|
|
|
|
|
|
Draw an AreaMode manipulator in an ugly way.
|
|
|
|
\warning this method is part of the \e DrawUgly series of functions, which is a \b TEMPORARY solution, used while waiting for the \e DrawBeautiful series...
|
|
|
|
@param tb the manipulator.
|
|
|
|
@param points AreaMode's points.
|
|
|
|
@param status AreaMode's status.
|
|
|
|
@param old_status AreaMode's old status.
|
|
|
|
@param plane AreaMode's plane.
|
|
|
|
@param path AreaMode's path.
|
|
|
|
@param rubberband_handle AreaMode's rubberband handle.
|
|
|
|
*/
|
|
|
|
void DrawUglyAreaMode(Trackball * tb,const std::vector < Point3f > &points,
|
2007-05-15 16:57:34 +02:00
|
|
|
Point3f status,Point3f old_status,Plane3f plane,
|
2007-07-10 00:41:22 +02:00
|
|
|
const std::vector < Point3f > &path,Point3f rubberband_handle)
|
2007-05-15 16:57:34 +02:00
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glPushAttrib (GL_ALL_ATTRIB_BITS);
|
|
|
|
// go to world coords
|
|
|
|
glTranslate (tb->center);
|
|
|
|
glMultMatrix (tb->track.InverseMatrix ());
|
|
|
|
glTranslate (-tb->center);
|
2007-07-10 00:41:22 +02:00
|
|
|
prepare_attrib();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.9f, 0.9f, 0.2f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glLineWidth(2.0);
|
|
|
|
glBegin(GL_LINE_LOOP);
|
2007-07-10 00:41:22 +02:00
|
|
|
for (std::vector < Point3f >::const_iterator i = points.begin (); i != points.end (); ++i){
|
2007-05-15 16:57:34 +02:00
|
|
|
glVertex(*i);
|
|
|
|
}
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.0f, 0.9f, 0.2f);
|
|
|
|
glLineWidth(1.2f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINE_STRIP);
|
2007-07-10 00:41:22 +02:00
|
|
|
for (std::vector < Point3f >::const_iterator i = path.begin (); i != path.end (); ++i){
|
2007-05-15 16:57:34 +02:00
|
|
|
glVertex(*i);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glColor3f(1,0,1);
|
|
|
|
glPointSize(8.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(status);
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.6f, 0.0f, 0.6f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glPointSize(7.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(old_status);
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.6f, 0.0f, 0.0f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glPointSize(6.0);
|
|
|
|
glBegin(GL_POINTS);
|
|
|
|
glVertex(rubberband_handle);
|
|
|
|
glEnd();
|
|
|
|
glLineWidth(1.0);
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex(rubberband_handle);
|
|
|
|
glVertex(status);
|
|
|
|
glEnd();
|
|
|
|
Point3f p0,d1,d2,norm;
|
|
|
|
norm=plane.Direction();
|
|
|
|
p0=plane.Projection(Point3f(0,0,0));
|
|
|
|
d1=Point3f(0,1,0);
|
|
|
|
if(norm == d1 || norm == -d1)
|
|
|
|
d1 = Point3f(1,0,0);
|
|
|
|
d2=plane.Projection(d1);
|
2008-10-27 20:35:17 +01:00
|
|
|
d1=(d2 - p0).normalized();
|
|
|
|
d2=(d1 ^ norm).normalized();
|
2007-05-15 16:57:34 +02:00
|
|
|
glLineWidth(3.0);
|
2007-05-28 10:10:47 +02:00
|
|
|
glColor3f(0.2f, 0.2f, 0.9f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex(p0);
|
|
|
|
glVertex(p0+norm);
|
|
|
|
glEnd();
|
2007-05-28 10:10:47 +02:00
|
|
|
glLineWidth(0.1f);
|
|
|
|
for(float i=0.5f;i<100.0f; i+=0.7f){
|
2007-05-15 16:57:34 +02:00
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
for(int a=0;a<360;a+=10){
|
2007-05-28 10:10:47 +02:00
|
|
|
float f0=i*cosf((float(M_PI)*float(a))/180.0f);
|
|
|
|
float f1=i*sinf((float(M_PI)*float(a))/180.0f);
|
2007-05-15 16:57:34 +02:00
|
|
|
glVertex(p0+(d1*f0)+(d2*f1));
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
glPopAttrib ();
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} //end namespace trackutils
|
|
|
|
|
|
|
|
} //end namespace vcg
|
|
|
|
|
|
|
|
#endif //TRACKUTILS_H
|