//---------------------------------------------------------------------------- // 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 ; }