Files
EgtGraphics/SceneCamera.cpp
T

460 lines
14 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2013-2014
//----------------------------------------------------------------------------
// File : SceneCamera.cpp Data : 10.02.14 Versione : 1.5b1
// Contenuto : Implementazione della gestione camera della classe scena.
//
//
//
// Modifiche : 10.02.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "Scene.h"
#include "/EgtDev/Include/EgtILogger.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EGkFrame3d.h"
using namespace std ;
//--------------------------- Constants --------------------------------------
static const double MIN_DIST_CAMERA = 10 ;
static const double STD_DIST_CAMERA = 1000 ;
static const double MIN_HALF_WIDTH_STD = 0.7 ;
static const double MAX_HALF_WIDTH_STD = 180000 ;
static const double MIN_HALF_HEIGHT_STD = 0.5 ;
static const double MAX_HALF_HEIGHT_STD = 140000 ;
//----------------------------------------------------------------------------
bool
Scene::SetCenter( const Point3d& ptCenter)
{
// assegno il punto
m_ptCenter = ptCenter ;
// invalido ExtView
m_bExtViewOk = false ;
// calcolo nuovi dati di Z clipping
CalcClippingPlanesFromExtView() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::SetCamera( double dAngVertDeg, double dAngOrizzDeg, double dDist)
{
// assegno la direzione e la distanza
m_vtDirCamera = FromSpherical( 1, dAngVertDeg, dAngOrizzDeg) ;
m_dDistCamera = dDist ;
if ( ! VerifyCamera())
return false ;
// se vista da sopra, impongo vtUp da angolo orizzontale
if ( abs( dAngVertDeg) < EPS_ANG_SMALL) {
m_vtUp = - FromPolar( 1, dAngOrizzDeg) ;
m_bUpOk = true ;
}
// lo stesso anche per vista da sotto
else if ( abs( dAngVertDeg - ANG_STRAIGHT) < EPS_ANG_SMALL) {
m_vtUp = FromPolar( 1, dAngOrizzDeg) ;
m_bUpOk = true ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::SetCamera( int nDir, double dDist)
{
switch ( nDir) {
case CT_TOP :
m_vtDirCamera.Set( 0, 0, 1) ;
break ;
case CT_FRONT :
m_vtDirCamera.Set( 0, -1, 0) ;
break ;
case CT_RIGHT :
m_vtDirCamera.Set( 1, 0, 0) ;
break ;
case CT_BACK :
m_vtDirCamera.Set( 0, 1, 0) ;
break ;
case CT_LEFT :
m_vtDirCamera.Set( -1, 0, 0) ;
break ;
case CT_BOTTOM :
m_vtDirCamera.Set( 0, 0, -1) ;
break ;
case CT_ISO_SW :
m_vtDirCamera.Set( -SQRT1_3, -SQRT1_3, SQRT1_3) ;
break ;
case CT_ISO_SE :
m_vtDirCamera.Set( SQRT1_3, -SQRT1_3, SQRT1_3) ;
break ;
case CT_ISO_NE :
m_vtDirCamera.Set( SQRT1_3, SQRT1_3, SQRT1_3) ;
break ;
case CT_ISO_NW :
m_vtDirCamera.Set( -SQRT1_3, SQRT1_3, SQRT1_3) ;
break ;
case CT_CPLANE :
m_vtDirCamera = GetGridFrame().VersZ() ;
break ;
default :
return false ;
break ;
}
if ( nDir != CT_CPLANE)
m_vtDirCamera.Rotate( Z_AX, m_nOrizzOffsCamera * ANG_RIGHT) ;
m_dDistCamera = dDist ;
return VerifyCamera( nDir != CT_CPLANE) ;
}
//----------------------------------------------------------------------------
bool
Scene::VerifyCamera( bool bUseOrizzOffsCamera)
{
// verifico il versore
if ( ! m_vtDirCamera.Normalize())
m_vtDirCamera.Set( 0, 0, 1) ;
// verifico la distanza
if ( m_dDistCamera < EPS_SMALL)
m_dDistCamera = STD_DIST_CAMERA ;
else
m_dDistCamera = max( m_dDistCamera, MIN_DIST_CAMERA) ;
// ricalcolo direzione Up
m_bUpOk = false ;
if ( ! CalcDirUp( bUseOrizzOffsCamera))
return false ;
// ricalcolo ExtView
m_bExtViewOk = false ;
if ( ! CalcExtView())
return false ;
// calcolo nuovi dati di Z clipping
return CalcClippingPlanesFromExtView() ;
}
//----------------------------------------------------------------------------
void
Scene::GetCamera( double* pdAngVertDeg, double* pdAngOrizzDeg, double* pdDist) const
{
double dAngVertDeg ;
double dAngOrizzDeg ;
m_vtDirCamera.ToSpherical( nullptr, &dAngVertDeg, &dAngOrizzDeg) ;
if ( abs( dAngVertDeg) < EPS_ANG_SMALL) {
if ( m_bUpOk)
(-m_vtUp).ToSpherical( nullptr, nullptr, &dAngOrizzDeg) ;
else
dAngOrizzDeg = -90 ;
}
else if ( abs( dAngVertDeg - ANG_STRAIGHT) < EPS_ANG_SMALL) {
if ( m_bUpOk)
(m_vtUp).ToSpherical( nullptr, nullptr, &dAngOrizzDeg) ;
else
dAngOrizzDeg = 90 ;
}
if ( pdAngVertDeg != nullptr)
*pdAngVertDeg = dAngVertDeg ;
if ( pdAngOrizzDeg != nullptr)
*pdAngOrizzDeg = dAngOrizzDeg ;
if ( pdDist != nullptr)
*pdDist = m_dDistCamera ;
}
//----------------------------------------------------------------------------
int
Scene::GetCameraDir( void) const
{
Vector3d vtDir = m_vtDirCamera ;
vtDir.Rotate( Z_AX, - m_nOrizzOffsCamera * ANG_RIGHT) ;
if ( vtDir.IsZplus())
return CT_TOP ;
else if ( vtDir.IsYminus())
return CT_FRONT ;
else if ( vtDir.IsXplus())
return CT_RIGHT ;
else if ( vtDir.IsYplus())
return CT_BACK ;
else if ( vtDir.IsXminus())
return CT_LEFT ;
else if ( vtDir.IsZminus())
return CT_BOTTOM ;
else if ( AreSameVectorApprox( vtDir, Vector3d( - SQRT1_3, - SQRT1_3, SQRT1_3)))
return CT_ISO_SW ;
else if ( AreSameVectorApprox( vtDir, Vector3d( SQRT1_3, - SQRT1_3, SQRT1_3)))
return CT_ISO_SE ;
else if ( AreSameVectorApprox( vtDir, Vector3d( SQRT1_3, SQRT1_3, SQRT1_3)))
return CT_ISO_NE ;
else if ( AreSameVectorApprox( vtDir, Vector3d( - SQRT1_3, SQRT1_3, SQRT1_3)))
return CT_ISO_NW ;
else
return CT_NONE ;
}
//----------------------------------------------------------------------------
Point3d
Scene::GetProjectedCenter( void) const
{
Point3d ptVCen ;
if ( ! Project( m_ptCenter, ptVCen))
ptVCen.Set( 0, 0, 0) ;
return ptVCen ;
}
//----------------------------------------------------------------------------
bool
Scene::CalcDirUp( bool bUseOrizzOffsCamera)
{
// verifico se il calcolo è necessario
if ( m_bUpOk)
return true ;
// direzione perpendicolare giacente nel piano XY
// ( m_vtDirCamera è opposta alla direzione in cui si guarda)
Vector3d vtPerpXY = m_vtDirCamera ^ Z_AX ;
if ( ! vtPerpXY.Normalize()) {
vtPerpXY = -X_AX ;
if ( bUseOrizzOffsCamera)
vtPerpXY.Rotate( Z_AX, m_nOrizzOffsCamera * ANG_RIGHT) ;
}
// direzione Up
m_vtUp = vtPerpXY ^ m_vtDirCamera ;
m_bUpOk = m_vtUp.Normalize() ;
// invalido ExtView
m_bExtViewOk = false ;
return m_bUpOk ;
}
//----------------------------------------------------------------------------
bool
Scene::CalcCameraFrame( Frame3d& frView)
{
// verifico direzione camera Up
if ( ! CalcDirUp())
return false ;
// eseguo il calcolo
Vector3d vtZ = m_vtDirCamera ;
Vector3d vtY = m_vtUp ;
Vector3d vtX = vtY ^ vtZ ;
if ( ! frView.Set( m_ptCenter + m_dDistCamera * vtZ, vtX, vtY, vtZ))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::PanCamera( const Point3d& ptWinOld, const Point3d& ptWinNew)
{
// porto i due punti in coordinate mondo
double dZCenter = GetProjectedCenter().z ;
Point3d ptViewOld( ptWinOld.x, ptWinOld.y, dZCenter) ;
Point3d ptWorldOld ;
if ( ! UnProject( ptViewOld, ptWorldOld))
return false ;
Point3d ptViewNew( ptWinNew.x, ptWinNew.y, dZCenter) ;
Point3d ptWorldNew ;
if ( ! UnProject( ptViewNew, ptWorldNew))
return false ;
// calcolo lo spostamento tra i due punti
Vector3d vtMove = ptWorldNew - ptWorldOld ;
// applico questo spostamento al centro di vista
return SetCenter( GetCenter() - vtMove) ;
}
//----------------------------------------------------------------------------
bool
Scene::RotateCamera( const Point3d& ptWinOld, const Point3d& ptWinNew)
{
// angoli correnti della camera
double dAngVertDeg ;
double dAngOrizzDeg ;
GetCamera( &dAngVertDeg, &dAngOrizzDeg) ;
// incrementi
double dDeltaAngVertDeg = ( ptWinNew.y - ptWinOld.y) / m_nViewportH * 360 ;
double dDeltaAngOrizzDeg = ( ptWinNew.x - ptWinOld.x) / m_nViewportW * 360 ;
// calcolo nuovi angoli e limitazione dell'angolo verticale
const double MIN_ANG_VERT = 0.0 ;
const double MAX_ANG_VERT = 180.0 ;
dAngVertDeg -= dDeltaAngVertDeg ;
if ( dAngVertDeg < MIN_ANG_VERT)
dAngVertDeg = MIN_ANG_VERT ;
else if ( dAngVertDeg > MAX_ANG_VERT)
dAngVertDeg = MAX_ANG_VERT ;
dAngOrizzDeg -= dDeltaAngOrizzDeg ;
// imposto nuova direzione camera
return SetCamera( dAngVertDeg, dAngOrizzDeg, 0) ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomAll( void)
{
// aggiorno l'ingombro
UpdateExtension() ;
// traslo il centro di vista nel centro del box
Point3d ptExtCent ;
if ( ! m_b3ExtWorld.GetCenter( ptExtCent))
return false ;
m_ptCenter = ptExtCent ;
m_bExtViewOk = false ;
// calcolo nuovi dati di ingombro
CalcDimViewFromExtView() ;
CalcClippingPlanesFromExtView() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomObject( int nId)
{
// Verifico puntatore a DB geometrico
if ( m_pGeomDB == nullptr)
return false ;
// determino l'ingombro dell'oggetto/i in globale
BBox3d b3Obj ;
if ( nId == GDB_ID_SEL) {
int nMyId = m_pGeomDB->GetFirstSelectedObj() ;
while ( nMyId != GDB_ID_NULL) {
BBox3d b3Curr ;
if ( m_pGeomDB->GetGlobalBBox( nMyId, b3Curr, BBF_ONLY_VISIBLE))
b3Obj.Add( b3Curr) ;
nMyId = m_pGeomDB->GetNextSelectedObj() ;
}
}
else
m_pGeomDB->GetGlobalBBox( nId, b3Obj, BBF_ONLY_VISIBLE) ;
// recupero centro
Point3d ptCent ;
if ( ! b3Obj.GetCenter( ptCent))
return false ;
// determino le dimensioni di vista nel riferimento di vista
Frame3d frView ;
if ( ! CalcCameraFrame( frView))
return false ;
b3Obj.ToLoc( frView) ;
const double COEFF = 1.05 ;
double dHalfWidth = COEFF * ( b3Obj.GetMax().x - b3Obj.GetMin().x) / 2 ;
double dHalfHeight = COEFF * ( b3Obj.GetMax().y - b3Obj.GetMin().y) / 2 ;
// imposto il centro e le dimensioni di vista
m_ptCenter = ptCent ;
return AdjustDimView( dHalfWidth, dHalfHeight) ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomRadius( double dRadius)
{
// adatto le dimensioni a quelle della vista
return AdjustDimView( dRadius, dRadius) ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomChange( double dCoeff)
{
const double MIN_COEFF = 0.5 ;
const double MAX_COEFF = 2 ;
// controllo i limiti
if ( dCoeff < MIN_COEFF)
dCoeff = MIN_COEFF ;
else if ( dCoeff > MAX_COEFF)
dCoeff = MAX_COEFF ;
m_dHalfWidth *= dCoeff ;
m_dHalfHeight *= dCoeff ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomOnPoint( const Point3d& ptWin, double dCoeff)
{
// recupero la matrice viewport
GLint Viewport[4] ;
glGetIntegerv( GL_VIEWPORT, Viewport) ;
// range valori delle Viewport
double dLimInfHW = MIN_HALF_WIDTH_STD * Viewport[2] / 1152.0 ;
double dLimInfHH = MIN_HALF_HEIGHT_STD * Viewport[3] / 928.0 ;
double dLimSupHW = MAX_HALF_WIDTH_STD * Viewport[2] / 1152.0 ;
double dLimSupHH = MAX_HALF_WIDTH_STD * Viewport[3] / 928.0 ;
// controllo se i parametri di Zoom minimo e massimo sono rispettati, altrimenti esco
if ( m_dHalfWidth * dCoeff > dLimSupHW || m_dHalfHeight * dCoeff > dLimSupHH)
return true ;
if ( m_dHalfWidth * dCoeff < dLimInfHW || m_dHalfHeight * dCoeff < dLimInfHH)
return true ;
// porto il punto in coordinate mondo
Point3d ptView( ptWin.x, ptWin.y, GetProjectedCenter().z) ;
Point3d ptWorld ;
if ( ! UnProject( ptView, ptWorld))
return false ;
// modifico opportunamente il centro di vista
Point3d ptNewCen = ptWorld + ( GetCenter() - ptWorld) * dCoeff ;
SetCenter( ptNewCen) ;
// eseguo lo zoom
return ZoomChange( dCoeff) ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomWin( const Point3d& ptWin1, const Point3d& ptWin2)
{
// porto i punti in coordinate mondo
Point3d ptWorld1 ;
if ( ! UnProject( Point3d( ptWin1.x, ptWin1.y, GetProjectedCenter().z), ptWorld1))
return false ;
Point3d ptWorld2 ;
if ( ! UnProject( Point3d( ptWin2.x, ptWin2.y, GetProjectedCenter().z), ptWorld2))
return false ;
// recupero il riferimento della camera (vista)
Frame3d frView ;
if ( ! CalcCameraFrame( frView))
return false ;
// porto i punti in coordinate camera (vista)
Point3d ptView1 = GetToLoc( ptWorld1, frView) ;
Point3d ptView2 = GetToLoc( ptWorld2, frView) ;
// imposto il nuovo centro di vista
Point3d ptNewCen = 0.5 * ( ptWorld1 + ptWorld2) ;
SetCenter( ptNewCen) ;
// imposto il nuovo zoom
double dHalfWidth = 0.5 * abs( ptView1.x - ptView2.x) ;
double dHalfHeight = 0.5 * abs( ptView1.y - ptView2.y) ;
// adatto le dimensioni a quelle della vista
return AdjustDimView( dHalfWidth, dHalfHeight) ;
}
//----------------------------------------------------------------------------
void
Scene::GetOrthoCamParam( double* pdWidth, double* pdHeight, double* pdNear, double* pdFar) const
{
if ( pdWidth != nullptr)
*pdWidth = m_dHalfWidth ;
if ( pdHeight != nullptr)
*pdHeight = m_dHalfHeight ;
if ( pdNear != nullptr)
*pdNear = m_dZNear ;
if ( pdFar != nullptr)
*pdFar = m_dZFar ;
}