cgal/Tutorial/tutorial/Polyhedron/Qt/Subdivision/tool/Arcball.cpp

311 lines
7.3 KiB
C++

//********************************************
// Arcball.cpp
//********************************************
// class CArcball
//********************************************
// mmeyer@gg.caltech.edu
// Created : 09/22/00
// Modified : 09/22/00
//********************************************
#include <math.h>
#include <qgl.h>
#include "Arcball.h"
#define PI 3.14159265358979323846
//////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////
//////////////////////////////////////////////
// DATA
//////////////////////////////////////////////
//********************************************
// Clear
//********************************************
void
CArcball::Clear()
{
m_Center.Set(0.f,0.f,0.f);
m_Radius = 1.f;
m_Dragging = 0;
m_Mode = ARCBALL_ROTATE;
m_Show = 0;
m_QuatTotal.Set(1.f,0.f,0.f,0.f);
m_QuatCurrent.Set(1.f,0.f,0.f,0.f);
}
//********************************************
// Set
//********************************************
void
CArcball::Set(const float x, const float y, const float z,
const float r /* = 1 */)
{
m_Center.Set(x,y,z);
m_Radius = r;
}
//********************************************
// Set
//********************************************
void
CArcball::Set(CVector3d center, const float r /* = 1 */)
{
m_Center = center;
m_Radius = r;
}
//********************************************
// Set
//********************************************
void
CArcball::Set(CArcball &a)
{
m_Radius = a.m_Radius;
m_Dragging = a.m_Dragging;
m_Mode = a.m_Mode;
m_Show = a.m_Show;
m_VecDown.Copy(a.m_VecDown);
m_Center.Copy(a.m_Center);
m_QuatCurrent.Copy(a.m_QuatCurrent);
m_QuatTotal.Copy(a.m_QuatTotal);
}
//********************************************
// Set
//********************************************
void
CArcball::Set(CArcball *pA)
{
m_Radius = pA->m_Radius;
m_Dragging = pA->m_Dragging;
m_Mode = pA->m_Mode;
m_Show = pA->m_Show;
m_VecDown.Copy(pA->m_VecDown);
m_Center.Copy(pA->m_Center);
m_QuatCurrent.Copy(pA->m_QuatCurrent);
m_QuatTotal.Copy(pA->m_QuatTotal);
}
//********************************************
// GetMatrix
//********************************************
void
CArcball::GetMatrix(float *mat)
{
CQuaternion q = m_QuatCurrent * m_QuatTotal;
q.GetMatrix(mat);
mat[3] = m_Center[0];
mat[7] = m_Center[1];
mat[11] = m_Center[2];
}
//********************************************
// GetMatrix
//********************************************
CMatrix44
CArcball::GetMatrix()
{
CQuaternion q = m_QuatCurrent * m_QuatTotal;
CMatrix44 mat = q.GetMatrix();
mat[0][3] = m_Center[0];
mat[1][3] = m_Center[1];
mat[2][3] = m_Center[2];
return mat;
}
//********************************************
// BeginDrag
//********************************************
void
CArcball::BeginDrag(CVector3d& currentVec)
{
if(m_Mode == ARCBALL_NO_MOTION) return;
m_VecDown = currentVec;
m_Dragging = 1;
}
//********************************************
// EndDrag
//********************************************
void
CArcball::EndDrag(CVector3d& currentVec)
{
if(!m_Dragging) return;
Motion(currentVec);
if(m_Mode == ARCBALL_ROTATE)
{
m_QuatTotal = m_QuatCurrent * m_QuatTotal;
m_QuatCurrent.Clear();
}
m_VecDown.Clear();
m_Dragging = 0;
}
//********************************************
// Motion
//********************************************
void
CArcball::Motion(CVector3d& currentVec)
{
if(!m_Dragging) return;
if(m_Mode == ARCBALL_ROTATE)
{
m_QuatCurrent = CQuaternion(m_VecDown,currentVec);
}
else if(m_Mode == ARCBALL_TRANSLATE_XY)
{
m_Center += currentVec - m_VecDown;
m_VecDown = currentVec;
}
else if(m_Mode == ARCBALL_TRANSLATE_Z)
{
float zDisp = (m_VecDown[1] - currentVec[1])/30.0f; // tone down the speed
float zCurrent = m_Center[2];
m_Center.z(zCurrent + zDisp);
m_VecDown = currentVec;
}
}
//********************************************
// glDraw
//********************************************
int
CArcball::glDraw()
{
float mat[16];
CQuaternion q = m_QuatCurrent * m_QuatTotal;
q.Conjugate().GetMatrix(mat);
glTranslatef(m_Center[0],m_Center[1],m_Center[2]);
glMultMatrixf(mat);
if(m_Show)
{
glBegin(GL_POLYGON);
glVertex3f(-m_Radius, 0.f ,0.f);
glVertex3f( 0.f ,-m_Radius,0.f);
glVertex3f( m_Radius, 0.f ,0.f);
glVertex3f( 0.f , m_Radius,0.f);
glEnd();
}
return 1;
}
//********************************************
// IntersectSphere
//********************************************
int
CArcball::IntersectSphere(CVector3d& rayStart, CVector3d& rayDir,
CVector3d& result)
{
CVector3d q = rayStart - m_Center;
float a = rayDir.Dot(rayDir);
float b = 2.f*rayDir.Dot(q);
float c = q.Dot(q) - m_Radius*m_Radius;
float d = b*b - 4.f*a*c;
if(d < 0.f)
{
IntersectPlane(rayStart,rayDir,result);
result -= m_Center;
result.Normalize();
//TRACE("mVec : (%g,%g,%g)\n",result.x(),result.y(),result.z());
return 0;
}
float t1 = (-b+sqrt(d))/(2.f*a);
float t2 = (-b-sqrt(d))/(2.f*a);
if (t2 < 0.f) t2 = t1;
result = rayStart + t2 * rayDir - m_Center;
result.Normalize();
//TRACE("mVec : (%g,%g,%g)\n",result.x(),result.y(),result.z());
return 1;
}
//********************************************
// IntersectPlane
//********************************************
int
CArcball::IntersectPlane(CVector3d& rayStart, CVector3d& rayDir,
CVector3d& result, int whichPlane /* = 2 */)
{
float denom = rayDir[whichPlane];
if(denom == 0.f)
{
result = m_VecDown;
return 0;
}
CVector3d numerVec = m_Center - rayStart;
float t = (numerVec[whichPlane])/denom;
result = rayStart + t * rayDir;
if(t < 0.f)
{
result = m_VecDown;
return 0;
}
return 1;
}
//********************************************
// Intersect
//********************************************
int
CArcball::Intersect(CVector3d& rayStart, CVector3d& rayDir, CVector3d& result)
{
if(m_Mode == ARCBALL_ROTATE)
return IntersectSphere(rayStart,rayDir,result);
else if(m_Mode == ARCBALL_TRANSLATE_XY)
return IntersectPlane(rayStart,rayDir,result,2);
else if(m_Mode == ARCBALL_TRANSLATE_Z)
return IntersectPlane(rayStart,rayDir,result,2);
return 0;
}
//********************************************
// Intersect
//********************************************
CVector3d
CArcball::Intersect(int x, int y, CCamera& theCam, CViewport& vp)
{
int xRes = vp.xRes();
int yRes = vp.yRes();
int xc = (xRes + vp.oX())/2;
int yc = (yRes + vp.oY())/2;
float r = xRes - xc;
r = (yRes - yc) < r ? (yRes - yc) : r;
CVector3d theVec, p;
float screenWidth;
if(m_Mode == ARCBALL_ROTATE)
{
theVec.Set((x - xc)/r, (y - yc)/r, 0.f);
float len = theVec.Length();
if(len >= 1.f)
theVec /= len;
else
{
theVec.z(sqrt(1.f - len * len));
theVec.Normalize();
}
}
else if(m_Mode == ARCBALL_TRANSLATE_XY)
{
theVec.Set(((float)x)/xRes,((float)y)/yRes,0.f);
p = m_Center - theCam.GetPosition();
screenWidth = vp.GetAspectRatio() * 2.f
*tan((theCam.GetHeightAngle()/2.f)*(PI/180.));
theVec *= p.Dot(theCam.GetToward())*screenWidth;
}
else if(m_Mode == ARCBALL_TRANSLATE_Z)
{
theVec.Set(0.f,((float)y)/yRes,0.f);
theVec *= .3f*(theCam.GetFarDistance() - theCam.GetNearDistance());
}
return theVec;
}
// ** EOF **