ac78227f0b
- piccoli aggiustamenti su ZoomOnPoint e ZoomWin per impostazione centro vista.
636 lines
20 KiB
C++
636 lines
20 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/EGkFrame3d.h"
|
|
#include "/EgtDev/Include/EGnStringUtils.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include "/EgtDev/Include/EgtILogger.h"
|
|
|
|
|
|
using namespace std ;
|
|
|
|
//--------------------------- Constants --------------------------------------
|
|
static const double MIN_DIST_CAMERA = 10 ;
|
|
static const double STD_DIST_CAMERA = 1000 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::SetCameraType( bool bOrthoOrPersp)
|
|
{
|
|
m_bOrthographic = bOrthoOrPersp ;
|
|
// ricalcolo i parametri di vista
|
|
m_bDistOk = false ;
|
|
CalcDistCamera() ;
|
|
CalcClippingPlanesFromExtView() ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::SetZoomType( int nZoomMode)
|
|
{
|
|
if ( nZoomMode != ZT_STD && nZoomMode != ZT_DOLLY)
|
|
return false ;
|
|
m_nPerspZoomType = nZoomMode ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double
|
|
Scene::CalcMinCameraDistance()
|
|
{
|
|
double dMinDist = MIN_DIST_CAMERA ;
|
|
|
|
// nel caso di vista prospettica la distanza della camera deve garantire di non finire dentro gli oggetti
|
|
if ( ! m_bOrthographic) {
|
|
|
|
// calcolo il box di tutti gli oggetti visibili nel frame della camera
|
|
Frame3d frCamera ;
|
|
CalcCameraFrame( frCamera) ;
|
|
BBox3d b3Tot ;
|
|
if ( m_pGeomDB != nullptr)
|
|
m_pGeomDB->GetGlobalBBox( GDB_ID_ROOT, b3Tot, BBF_ONLY_VISIBLE) ;
|
|
b3Tot.ToLoc( frCamera) ;
|
|
|
|
// la distanza minima della camera è quella che garantisce di trovarsi ad una distanza pari almeno a PERSPECTIVE_NEAR_PLANE
|
|
// dalla faccia del box davanti alla camera
|
|
Point3d ptMax = b3Tot.GetMax() ;
|
|
ptMax.ToGlob( frCamera) ;
|
|
dMinDist = ( ptMax - m_ptCenter) * m_vtDirCamera + PERSPECTIVE_NEAR_PLANE + 10 * EPS_SMALL ;
|
|
}
|
|
|
|
return dMinDist ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::CalcDistCamera()
|
|
{
|
|
// verifico se il calcolo è necessario
|
|
if ( m_bDistOk)
|
|
return true ;
|
|
|
|
if ( m_dDistCamera < EPS_SMALL)
|
|
m_dDistCamera = STD_DIST_CAMERA ;
|
|
else {
|
|
double dMinDist = CalcMinCameraDistance() ;
|
|
if ( m_dDistCamera < dMinDist)
|
|
m_dDistCamera = dMinDist ;
|
|
}
|
|
m_bDistOk = true ;
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ed eventuale distanza
|
|
m_vtDirCamera = FromSpherical( 1, dAngVertDeg, dAngOrizzDeg) ;
|
|
if ( dDist > EPS_SMALL)
|
|
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) ;
|
|
|
|
// assegno eventuale distanza
|
|
if ( dDist > EPS_SMALL)
|
|
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) ;
|
|
|
|
// ricalcolo direzione Up
|
|
m_bUpOk = false ;
|
|
if ( ! CalcDirUp( bUseOrizzOffsCamera))
|
|
return false ;
|
|
|
|
// verifico la distanza
|
|
m_bDistOk = false ;
|
|
CalcDistCamera() ;
|
|
|
|
// 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 dOldZCenter ;
|
|
GetPixelZ( ptWinOld, dOldZCenter) ;
|
|
Point3d ptViewOld( ptWinOld.x, ptWinOld.y, dOldZCenter) ;
|
|
Point3d ptWorldOld ;
|
|
if ( ! UnProject( ptViewOld, ptWorldOld))
|
|
return false ;
|
|
double dNewZCenter ;
|
|
GetPixelZ( ptWinNew, dNewZCenter) ;
|
|
Point3d ptViewNew( ptWinNew.x, ptWinNew.y, dNewZCenter) ;
|
|
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
|
|
SetCenter( GetCenter() - vtMove) ;
|
|
// se dolly aggiusto la distanza per non entrare negli oggetti
|
|
if ( ! m_bOrthographic && m_nPerspZoomType == ZT_DOLLY)
|
|
CalcDistCamera() ;
|
|
else
|
|
m_bDistOk = true ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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() ;
|
|
|
|
if ( ! m_bOrthographic) {
|
|
if ( m_nPerspZoomType == ZT_DOLLY) {
|
|
// adatto la distanza della camera in modo che il fov resti al valore standard
|
|
m_dDistCamera = m_dHalfHeight / tan( PERSPECTIVE_STD_FOV * 0.5 * DEGTORAD) + ( m_b3ExtView.GetMax().z - m_b3ExtView.GetMin().z) * 0.5 ;
|
|
}
|
|
else {
|
|
// aggiusto la distanza della camera
|
|
m_b3ExtView.GetDiameter( m_dDistCamera) ;
|
|
|
|
// il valore di m_dHalfHeight calcolato dal box non garantisce che l'oggetto sia interamente contenuto nel frustum
|
|
// perchè è il valore in corrispondenza della faccia del box davanti alla camera. Per il calcolo del fov m_dHalfHeight
|
|
// deve essere calcolato in corrispondenza di m_ptCenter
|
|
// distanza della camera dalla faccia davanti del box
|
|
double dDist = m_dDistCamera - ( m_b3ExtView.GetMax().z - m_b3ExtView.GetMin().z) * 0.5 ;
|
|
// aggiorno le dimensioni
|
|
double dAspect = m_dHalfWidth / m_dHalfHeight ;
|
|
m_dHalfHeight = m_dHalfHeight / dDist * m_dDistCamera ;
|
|
m_dHalfWidth = m_dHalfHeight * dAspect ;
|
|
|
|
}
|
|
}
|
|
// la distanza della camera è calcolata correttamente
|
|
m_bDistOk = true ;
|
|
|
|
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 ;
|
|
if ( ! AdjustDimView( dHalfWidth, dHalfHeight))
|
|
return false ;
|
|
|
|
if ( ! m_bOrthographic) {
|
|
// cfr conti analoghi in ZoomAll
|
|
if ( m_nPerspZoomType == ZT_DOLLY) {
|
|
m_dDistCamera = m_dHalfHeight / tan( PERSPECTIVE_STD_FOV * 0.5 * DEGTORAD) + ( b3Obj.GetMax().z - b3Obj.GetMin().z) * 0.5 ;
|
|
}
|
|
else {
|
|
// verifico di non finire dentro l'oggetto
|
|
double dDiam ; b3Obj.GetDiameter( dDiam) ;
|
|
if ( m_dDistCamera < dDiam * 0.5)
|
|
m_dDistCamera = dDiam * 0.5 ;
|
|
// distanza della camera dalla faccia davanti del box
|
|
double dDist = m_dDistCamera - ( b3Obj.GetMax().z - b3Obj.GetMin().z) * 0.5 ;
|
|
// ricalcolo le dimensioni
|
|
double dAspect = m_dHalfWidth / m_dHalfHeight ;
|
|
m_dHalfHeight = m_dHalfHeight / dDist * m_dDistCamera ;
|
|
m_dHalfWidth = m_dHalfHeight * dAspect ;
|
|
}
|
|
}
|
|
// la distanza della camera è calcolata per non finire dentro gli oggetti
|
|
m_bDistOk = true ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::ZoomRadius( double dRadius)
|
|
{
|
|
// adatto le dimensioni a quelle della vista
|
|
if ( ! AdjustDimView( dRadius, dRadius))
|
|
return false ;
|
|
|
|
// per il dolly va modificata la distanza dalla camera
|
|
if ( ! m_bOrthographic && m_nPerspZoomType == ZT_DOLLY) {
|
|
m_dDistCamera = m_dHalfHeight / tan( PERSPECTIVE_STD_FOV * 0.5 * DEGTORAD) ;
|
|
// verifico la distanza della camera
|
|
CalcDistCamera() ;
|
|
}
|
|
else
|
|
m_bDistOk = true ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::ZoomChange( double dCoeff)
|
|
{
|
|
const double MIN_COEFF = 0.5 ;
|
|
const double MAX_COEFF = 2 ;
|
|
|
|
// cambio le dimensioni di zoom
|
|
if ( ! m_bOrthographic && m_nPerspZoomType == ZT_DOLLY) {
|
|
// per il dolly va modificata la distanza della camera
|
|
m_dDistCamera *= dCoeff ;
|
|
}
|
|
else {
|
|
// controllo i limiti
|
|
dCoeff = clamp( dCoeff, MIN_COEFF, MAX_COEFF) ;
|
|
m_dHalfWidth *= dCoeff ;
|
|
m_dHalfHeight *= dCoeff ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::ZoomOnPoint( const Point3d& ptWin, double dCoeff)
|
|
{
|
|
// leggo Z del pixel
|
|
double dWinZ ;
|
|
GetPixelZ( ptWin, dWinZ) ;
|
|
|
|
// porto il punto in coordinate mondo
|
|
Point3d ptView( ptWin.x, ptWin.y, dWinZ) ;
|
|
Point3d ptWorld ;
|
|
if ( ! UnProject( ptView, ptWorld))
|
|
return false ;
|
|
|
|
// modifico opportunamente il centro di vista
|
|
Point3d ptOldCen = m_ptCenter ;
|
|
Point3d ptNewCen = ptWorld + ( m_ptCenter - ptWorld) * dCoeff ;
|
|
ptNewCen += ( ptWorld - ptNewCen) * m_vtDirCamera * m_vtDirCamera ;
|
|
SetCenter( ptNewCen) ;
|
|
m_bDistOk = true ;
|
|
|
|
if ( ! m_bOrthographic) {
|
|
if ( m_nPerspZoomType == ZT_DOLLY) {
|
|
// nel caso di dolly verifico se il nuovo zoom fa entrare negli oggetti
|
|
double dMinDist = CalcMinCameraDistance() ;
|
|
if ( m_dDistCamera * dCoeff < dMinDist) {
|
|
// adatto il coefficiente di zoom e ricalcolo il centro
|
|
dCoeff = dMinDist / m_dDistCamera ;
|
|
Point3d ptNewCenter = ptWorld + ( ptOldCen - ptWorld) * dCoeff ;
|
|
SetCenter( ptNewCenter) ;
|
|
}
|
|
}
|
|
else {
|
|
// nel caso standard verifico se il nuovo fov supera il valore massimo
|
|
if ( m_dHalfHeight * dCoeff / m_dDistCamera > PERSPECTIVE_TAN_MAX_FOV) {
|
|
// adatto il coefficiente di zoom e ricalcolo il centro
|
|
dCoeff = PERSPECTIVE_TAN_MAX_FOV * m_dDistCamera / m_dHalfHeight ;
|
|
Point3d ptNewCenter = ptWorld + ( ptOldCen - ptWorld) * dCoeff ;
|
|
SetCenter( ptNewCenter) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ZoomChange( dCoeff) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
Scene::ZoomWin( const Point3d& ptWin1, const Point3d& ptWin2)
|
|
{
|
|
// leggo Z del pixel
|
|
double dWinZ ;
|
|
GetPixelZ( Media( ptWin1, ptWin2), dWinZ) ;
|
|
|
|
// porto i punti in coordinate mondo
|
|
Point3d ptWorld1 ;
|
|
if ( ! UnProject( Point3d( ptWin1.x, ptWin1.y, dWinZ), ptWorld1))
|
|
return false ;
|
|
Point3d ptWorld2 ;
|
|
if ( ! UnProject( Point3d( ptWin2.x, ptWin2.y, dWinZ), 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
|
|
if ( ! AdjustDimView( dHalfWidth, dHalfHeight))
|
|
return false ;
|
|
|
|
// per il dolly va modificata la distanza della camera
|
|
if ( ! m_bOrthographic && m_nPerspZoomType == ZT_DOLLY) {
|
|
m_dDistCamera = m_dHalfHeight / tan( PERSPECTIVE_STD_FOV * 0.5 * DEGTORAD) ;
|
|
CalcDistCamera() ;
|
|
}
|
|
else
|
|
m_bDistOk = true ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
}
|