Files
EgtGraphics/SceneCamera.cpp

434 lines
13 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 ;
//----------------------------------------------------------------------------
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 ;
}
m_dDistCamera = dDist ;
return VerifyCamera() ;
}
//----------------------------------------------------------------------------
bool
Scene::VerifyCamera( void)
{
// 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) ;
// invalido Up e ExtView
m_bUpOk = false ;
m_bExtViewOk = false ;
// calcolo nuovi dati di Z clipping
CalcClippingPlanesFromExtView() ;
return true ;
}
//----------------------------------------------------------------------------
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
{
if ( m_vtDirCamera.IsZplus())
return CT_TOP ;
else if ( m_vtDirCamera.IsYminus())
return CT_FRONT ;
else if ( m_vtDirCamera.IsXplus())
return CT_RIGHT ;
else if ( m_vtDirCamera.IsYplus())
return CT_BACK ;
else if ( m_vtDirCamera.IsXminus())
return CT_LEFT ;
else if ( m_vtDirCamera.IsZminus())
return CT_BOTTOM ;
else if ( AreSameVectorApprox( m_vtDirCamera, Vector3d( - SQRT1_3, - SQRT1_3, SQRT1_3)))
return CT_ISO_SW ;
else if ( AreSameVectorApprox( m_vtDirCamera, Vector3d( SQRT1_3, - SQRT1_3, SQRT1_3)))
return CT_ISO_SE ;
else if ( AreSameVectorApprox( m_vtDirCamera, Vector3d( SQRT1_3, SQRT1_3, SQRT1_3)))
return CT_ISO_NE ;
else if ( AreSameVectorApprox( m_vtDirCamera, 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( void)
{
// 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()) {
if ( m_vtDirCamera.z < 0)
vtPerpXY = X_AX ;
else
vtPerpXY = - X_AX ;
}
// 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 ;
// cambio le dimensioni di zoom
m_dHalfWidth *= dCoeff ;
m_dHalfHeight *= dCoeff ;
return true ;
}
//----------------------------------------------------------------------------
bool
Scene::ZoomOnPoint( const Point3d& ptWin, double dCoeff)
{
// 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 ;
}