/* * CCamera.cpp * $Id: CCamera.cpp,v 1.3 2002/02/06 12:47:09 guenth Exp $ * * Copyright (C) 1999, 2000 Markus Janich * * This program is free software; you can redistribute it and/or modify * 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * As a special exception to the GPL, the QGLViewer authors (Markus * Janich, Michael Meissner, Richard Guenther, Alexander Buck and Thomas * Woerner) give permission to link this program with Qt (non-)commercial * edition, and distribute the resulting executable, without including * the source code for the Qt (non-)commercial edition in the source * distribution. * */ // Qt /////// // System /////////// // Own /////////// #include "CCamera.h" // Function : rotate // Parameters: double rdAngle, CV3D cAxis, bool global. // Purpose : rotates the camera around an axis which goes through the eyepoint // or the reference point (point of interest). See docu for details. // Comments : See docu for details. void CCamera::rotate(double rdAngle, CV3D cAxis, bool global) /*********************************************************************/ { CV3D cRefPoint = m_cRefPoint.getCV3D(); CV3D cEyePos = m_cEyePos.getCV3D(); CMat4D rot_matrix = CMat4D::PRotate(cAxis, (rdAngle/180.0)*M_PI); // update values of this camera if(global) { setEyePos(CP3D( rot_matrix * CMat4D::PTranslate(-cRefPoint) * m_cEyePos) + cRefPoint); } else { setRefPoint(CP3D(rot_matrix * CMat4D::PTranslate(-cEyePos) * m_cRefPoint) + cEyePos); } m_cViewUp = rot_matrix * m_cViewUp; m_cViewUp.normalize(); m_fValidViewRight = m_fValidViewDir = false; // set valid flags to false } // Function : translate // Parameters: CV3D vDiff // Purpose : Move the camera relative to the current position // Comments : See docu for details. void CCamera::translate(CV3D vDiff) /*********************************************************************/ { setEyePos(getEyePos() + vDiff); setRefPoint(getRefPoint() + vDiff); } // Function : setEyePos // Parameters: const CP3D &cEyePos // Purpose : Set a new eye-point. // Comments : See docu for details. void CCamera::setEyePos(const CP3D &cEyePos) /*********************************************************************/ { double rdOrthogonalDistance; m_fValidViewRight = m_fValidViewDir = false; m_cEyePos = cEyePos; CP3D c = m_cBBox.getCenter(); CV3D v = getViewDir(); rdOrthogonalDistance = (c[0]-m_cEyePos[0])*v[0] + (c[1]-m_cEyePos[1])*v[1] + (c[2]-m_cEyePos[2])*v[2]; m_rdNearPlane = rdOrthogonalDistance - m_cBBox.getOuterRadius(); if (m_rdNearPlane < 0.01) { m_rdNearPlane = 0.01; } m_rdFarPlane = rdOrthogonalDistance + m_cBBox.getOuterRadius(); } // Function : getViewDir // Parameters: // Purpose : // Comments : See docu for details. const CV3D& CCamera::getViewDir() const /*********************************************************************/ { if(!m_fValidViewDir) { m_cViewDir = m_cRefPoint - m_cEyePos; m_cViewDir.normalize(); m_fValidViewDir = true; } return m_cViewDir; } // Function : getViewRight // Parameters: // Purpose : // Comments : See docu for details. const CV3D& CCamera::getViewRight() const /*********************************************************************/ { if(!m_fValidViewRight) { m_cViewRight = getViewDir() | m_cViewUp; m_cViewRight.normalize(); m_fValidViewRight = true; } return m_cViewRight; } // Function : getVVolume // Parameters: double array[6] // Purpose : returns the parameters of the view volume needed for // OpenGL's glFrustum or glOrtho call // Comments : See docu for details. void CCamera::getVVolume(double array[6]) const /*********************************************************************/ { double rdXClip, rdYClip; if(m_rdRatio>=1.0) { rdYClip = tan((m_rdVerAngle/360.0)*M_PI) * m_rdNearPlane; rdXClip = rdYClip*m_rdRatio; } else { rdXClip = tan((m_rdVerAngle/360.0)*M_PI) * m_rdNearPlane; rdYClip = rdXClip/m_rdRatio; } array[0] = -rdXClip; // left clipplane array[1] = rdXClip; // right clipplane array[2] = -rdYClip; // bottom clipplane array[3] = rdYClip; // top clipplane array[4] = m_rdNearPlane; array[5] = m_rdFarPlane; } // Function : getVPParams // Parameters: CV3D &origin, CV3D &xStep, CV3D &yStep, int rdXSize, int rdYSize // Purpose : returns some paramters to built a viewplane for raycasting // Comments : See docu for details. void CCamera::getVPParams(CP3D &origin, CV3D &xStep, CV3D &yStep, int nXSize, int nYSize) const /*********************************************************************/ { CP3D cRefVec; CV3D cViewRight, cViewDir; double ardVVolume[6]; double rdDist, rdHorRad, rdVerRad,rdRatio; rdRatio = (double)nXSize/nYSize; cViewRight = getViewRight(); cViewDir = getViewDir(); rdVerRad = m_rdVerAngle*(M_PI/180.0); rdHorRad = rdVerRad*rdRatio; rdDist = 1.0; if (m_CameraType == perspective) { // calculate offset vectors. xStep = cViewRight * ( sin(rdHorRad/2) * rdDist / (nXSize>>1)); yStep = m_cViewUp * -( sin(rdVerRad/2) * rdDist / (nYSize>>1)); // calculate point of origin (upper left) cRefVec = m_cEyePos + cViewDir * rdDist; // go left cRefVec -= cViewRight * sin(rdHorRad/2.0) * rdDist; // go up cRefVec += m_cViewUp * sin(rdVerRad/2.0) * rdDist; origin = cRefVec;; } else { getVVolume(ardVVolume); // calculate offset vectors. xStep = cViewRight * ((ardVVolume[1] - ardVVolume[0]) / nXSize); yStep = m_cViewUp * -((ardVVolume[3] - ardVVolume[2]) / nYSize); // calculate point of origin (upper left) cRefVec = m_cEyePos + cViewDir * rdDist; cRefVec = cRefVec - (nXSize>>1) * xStep; cRefVec = cRefVec - (nYSize>>1) * yStep; origin = cRefVec; } } // Function : getModelview // Parameters: // Purpose : // Comments : CMat4D CCamera::getModelview() const { CP3D ref = getRefPoint(); CP3D eye = getEyePos(); CV3D vup = getViewUp(); vup.normalize(); CV3D f = ref-eye; f.normalize(); CV3D s = f | vup; CV3D u = s | f; CMat4D rotate(s[0], u[0], -f[0], 0, s[1], u[1], -f[1], 0, s[2], u[2], (-f[2]), 0, 0, 0, 0, 1); CMat4D mv = rotate*CMat4D::PTranslate(-eye.getCV3D()); return mv; } // Function : getOrtho // Parameters: // Purpose : // Comments : CMat4D CCamera::getOrtho() const { double vv[6]; getVVolume(vv); double tx = -(vv[1]+vv[0])/(vv[1]-vv[0]); double ty = -(vv[3]+vv[2])/(vv[3]-vv[2]); double tz = -(vv[5]+vv[4])/(vv[5]-vv[4]); CMat4D ortho(2/(vv[1]-vv[0]), 0, 0, 0, 0, 2/(vv[3]-vv[2]), 0, 0, 0, 0, -2/(vv[5]-vv[4]), 0, tx, ty, tz, 1); return ortho; } // Function : getFrustrum // Parameters: // Purpose : // Comments : CMat4D CCamera::getFrustrum() const { double vv[6]; getVVolume(vv); double A = (vv[1]+vv[0])/(vv[1]-vv[0]); double B = (vv[3]+vv[2])/(vv[3]-vv[2]); double C = -(vv[5]+vv[4])/(vv[5]-vv[4]); double D = -2*vv[5]*vv[4]/(vv[5]-vv[4]); CMat4D frustrum(2*vv[4]/(vv[1]-vv[0]), 0, 0, 0, 0, 2*vv[4]/(vv[3]-vv[2]), 0, 0, A, B, C,-1, 0, 0, D, 0); return frustrum; } // Function : getProjection // Parameters: // Purpose : // Comments : CMat4D CCamera::getProjection() const { if (getCameraType() == CCamera::orthographic) { return getOrtho(); } else /* if (getCameraType() == CCamera::perspective) */ { return getFrustrum(); } } // Function : getVPTrans // Parameters: // Purpose : // Comments : CMat4D CCamera::getVPTrans(int nXSize, int nYSize) const { CMat4D vptrans = (CMat4D::PTranslate(nXSize/2, nYSize/2, 0) *CMat4D::PScale(nXSize/2, -nYSize/2, 1.0)); return vptrans; } // Function : viewAll // Parameters: // Purpose : Modifies the camera that the bounding box fits // within the currently defined view frustum. // Comments : See docu for details. void CCamera::viewAll() /*********************************************************************/ { float rfDistance = m_cBBox.getOuterRadius()/tan(m_rdVerAngle/2.0*M_PI/180.0); setRefPoint(m_cBBox.getCenter()); setEyePos(m_cRefPoint + (getViewDir() * -rfDistance)); } // Function : print // Parameters: void // Purpose : Prints the camera parameters to standard output // Comments : void CCamera::print(void) /*********************************************************************/ { cout << m_cBBox << endl; cout << m_cEyePos << endl; cout << m_cRefPoint << endl; cout << m_cViewUp << endl; cout << m_cViewDir << endl; return; }