void CameraTransitionController::Update(float dt)
            {
                if(!IsTransitioning())
                {
                    return;
                }

                ICameraTransitionStage* pCurrentStage = m_transitionStages.front();
                pCurrentStage->Update(dt);
                if(pCurrentStage->StageIsComplete() && !m_appCameraController.IsTransitionInFlight())
                {
                    pCurrentStage->End();
                    Eegeo_DELETE pCurrentStage;
                    m_transitionStages.pop();
                    
                    if(m_transitionStages.size() > 0)
                    {
                        pCurrentStage = m_transitionStages.front();
                        pCurrentStage->Start();
                    }
                    else
                    {
                        StopCurrentTransition();
                    }
                }
                else if(pCurrentStage->StageHasFailed())
                {
                    StopCurrentTransition();
                }
            }
void CameraTransitioner::Update(float dt)
{
	if(!IsTransitioning())
	{
		return;
	}

	m_transitionTime += dt;
	double transitionParam = Eegeo::Math::SmoothStep(0.0, 1.0, m_transitionTime / m_transitionDuration);

	float interpolatedDistance = Eegeo::Math::Lerp(m_startInterestDistance, m_endInterestDistance, transitionParam);
	Eegeo::dv3 interpolatedInterestPosition = Eegeo::dv3::Lerp(m_startTransitionInterestPoint, m_endTransitionInterestPoint, transitionParam);
	if(interpolatedInterestPosition.LengthSq() < Eegeo::Space::EarthConstants::RadiusSquared)
	{
		interpolatedInterestPosition = interpolatedInterestPosition.Norm() * Eegeo::Space::EarthConstants::Radius;
	}

	float interpolatedHeading = ((1-transitionParam) * m_startTransitionHeading) + (transitionParam * m_endTransitionHeading);

	Eegeo::v3 interpolatedHeadingVector = ComputeHeadingVector(interpolatedInterestPosition, interpolatedHeading);

	Eegeo::Space::EcefTangentBasis newInterestBasis(interpolatedInterestPosition, interpolatedHeadingVector);
	m_cameraController.SetView(newInterestBasis, interpolatedDistance);

	if(transitionParam >= 1.f)
	{
		StopCurrentTransition();
	}
}
            void CameraTransitionController::Update(float dt)
            {
                if(!IsTransitioning())
                {
                    return;
                }

                m_transitionTime += dt;
                float transitionParam = Eegeo::Math::SmoothStep(0.f, 1.f, m_transitionTime / m_transitionDuration);

                float interpolatedDistance = Eegeo::Math::Lerp(m_startInterestDistance, m_endInterestDistance, transitionParam);
                Eegeo::dv3 interpolatedInterestPosition = Eegeo::dv3::Lerp(m_startTransitionInterestPointEcef, m_endTransitionInterestPointEcef, transitionParam);
                float currentAssumedAltitude = 0;

                m_terrainHeightProvider.TryGetHeight(interpolatedInterestPosition, 0, currentAssumedAltitude);

                if(interpolatedInterestPosition.Length() < Eegeo::Space::EarthConstants::Radius + currentAssumedAltitude)
                {
                    interpolatedInterestPosition = interpolatedInterestPosition.Norm() * (Eegeo::Space::EarthConstants::Radius + currentAssumedAltitude);
                }

                float interpolatedHeading = Eegeo::Math::Lerp<float>(m_startInterestHeading, m_endInterestHeading, transitionParam);
                Eegeo::v3 interpolatedHeadingVector = ComputeHeadingVector(interpolatedInterestPosition, interpolatedHeading);

                Eegeo::Space::EcefTangentBasis newInterestBasis(interpolatedInterestPosition, interpolatedHeadingVector);
                m_cameraController.SetView(newInterestBasis, interpolatedDistance);

                if(transitionParam >= 1.f)
                {
                    StopCurrentTransition();
                }
            }
void CameraTransitioner::StartTransitionTo(Eegeo::dv3 newInterestPoint, double distanceFromInterest, float newHeading, bool jumpIfFarAway)
{
	if(IsTransitioning())
	{
		StopCurrentTransition();
	}

	if(jumpIfFarAway && ShouldJumpTo(newInterestPoint))
	{
		Eegeo::Space::EcefTangentBasis newInterestBasis;
		Eegeo::Camera::CameraHelpers::EcefTangentBasisFromPointAndHeading(newInterestPoint, Eegeo::Math::Rad2Deg(newHeading), newInterestBasis);
		m_cameraController.SetView(newInterestBasis, distanceFromInterest);
		StopCurrentTransition();
		return;
	}

	const Eegeo::Space::EcefTangentBasis& currentInterestBasis = m_cameraController.GetInterestBasis();
	m_startTransitionInterestPoint = currentInterestBasis.GetPointEcef();
	m_startInterestDistance = m_cameraController.GetDistanceToInterest();

	float bearingRadians = Eegeo::Camera::CameraHelpers::GetAbsoluteBearingRadians(currentInterestBasis.GetPointEcef(), currentInterestBasis.GetForward());
	m_startTransitionHeading = bearingRadians;
	m_endTransitionHeading = newHeading;
	m_endTransitionInterestPoint = newInterestPoint;
	m_endInterestDistance = distanceFromInterest;
	m_transitionTime = 0.f;

	const float CAMERA_TRANSITION_SPEED_IN_METERS_PER_SECOND = 100.0f;
	const float MIN_TRANSITION_TIME = 2.0f;
	const float MAX_TRANSITION_TIME = 10.0f;
	float distance = (m_endTransitionInterestPoint - m_startTransitionInterestPoint).Length();

	m_transitionDuration = Eegeo::Clamp(distance/CAMERA_TRANSITION_SPEED_IN_METERS_PER_SECOND, MIN_TRANSITION_TIME, MAX_TRANSITION_TIME);

	m_isTransitioning = true;

	if(abs(m_endTransitionHeading - m_startTransitionHeading) > M_PI)
	{
		if(m_endTransitionHeading > m_startTransitionHeading)
			m_endTransitionHeading -= 2 * M_PI;
		else
			m_startTransitionHeading -= 2 * M_PI;
	}

}
            void CameraTransitionController::StartTransitionTo(Eegeo::dv3 newInterestPoint, float distanceFromInterest, float newHeadingRadians, bool jumpIfFar)
            {
                if(IsTransitioning())
                {
                    StopCurrentTransition();
                }

                m_navigationService.SetGpsMode(Eegeo::Location::NavigationService::GpsModeOff);

                if(jumpIfFar && ShouldJumpTo(newInterestPoint))
                {
                    Eegeo::Space::EcefTangentBasis newInterestBasis;
                    Eegeo::Camera::CameraHelpers::EcefTangentBasisFromPointAndHeading(newInterestPoint,
                            Eegeo::Math::Rad2Deg(newHeadingRadians),
                            newInterestBasis);
                    m_cameraController.SetView(newInterestBasis, distanceFromInterest);
                    return;
                }

                const Eegeo::Space::EcefTangentBasis& currentInterestBasis = m_cameraController.GetInterestBasis();
                m_startTransitionInterestPointEcef = currentInterestBasis.GetPointEcef();
                m_startInterestDistance = m_cameraController.GetDistanceToInterest();
                m_startInterestHeading = Eegeo::Camera::CameraHelpers::GetAbsoluteBearingRadians(currentInterestBasis.GetPointEcef(),
                                         currentInterestBasis.GetForward());;

                m_endTransitionInterestPointEcef = newInterestPoint;
                m_endInterestDistance = distanceFromInterest;
                m_endInterestHeading = newHeadingRadians;

                m_transitionTime = 0.0f;

                const float CAMERA_TRANSITION_SPEED_IN_METERS_PER_SECOND = 1000.0f;
                const float MIN_TRANSITION_TIME = 0.5f;
                const float MAX_TRANSITION_TIME = 2.0f;
                float distance = (m_endTransitionInterestPointEcef - m_startTransitionInterestPointEcef).ToSingle().Length();

                m_transitionDuration = Eegeo::Clamp(distance/CAMERA_TRANSITION_SPEED_IN_METERS_PER_SECOND, MIN_TRANSITION_TIME, MAX_TRANSITION_TIME);

                m_isTransitioning = true;

                if(std::abs(m_endInterestHeading - m_startInterestHeading) > Eegeo::Math::kPI)
                {
                    if(m_endInterestHeading > m_startInterestHeading)
                        m_endInterestHeading -= 2.f * Eegeo::Math::kPI;
                    else
                        m_startInterestHeading -= 2.f * Eegeo::Math::kPI;
                }
            }
 void CameraTransitionController::StartTransitionTo(const Eegeo::dv3& newInterestPoint,
                                                    float distanceFromInterest,
                                                    float newHeadingRadians,
                                                    const Eegeo::Resources::Interiors::InteriorId& interiorId,
                                                    int targetFloorIndex,
                                                    bool jumpIfFar)
 {
     if(IsTransitioning())
     {
         StopCurrentTransition();
     }
     
     m_navigationService.SetGpsMode(Eegeo::Location::NavigationService::GpsModeOff);
     
     if(m_appModeModel.GetAppMode() == ExampleApp::AppModes::SdkModel::InteriorMode)
     {
         const double exitInteriorDistanceSquared = 100*100;
         double interestDifferenceSquared = (m_interiorsCameraController.GetInterestLocation() - newInterestPoint).LengthSq();
         if(m_interiorSelectionModel.GetSelectedInteriorId() == interiorId)
         {
             Eegeo_ASSERT(interiorId != Eegeo::Resources::Interiors::InteriorId::NullId(), "Invalid state. Have selected null Interior while in Interior mode");
             EnqueueTransitionToInteriorStage(newInterestPoint, distanceFromInterest, interiorId, targetFloorIndex);
             StartQueuedTransition();
             return;
         }
         else if(interiorId != Eegeo::Resources::Interiors::InteriorId::NullId() && interestDifferenceSquared < exitInteriorDistanceSquared)
         {
             EnqueueTransitionToInteriorPointStage(newInterestPoint, distanceFromInterest, newHeadingRadians, interiorId, targetFloorIndex, jumpIfFar);
             StartQueuedTransition();
             return;
         }
         else
         {
             EnqueueExitInteriorStage();
         }
     }
     
     EnqueueTransitionToPointStage(newInterestPoint, distanceFromInterest, newHeadingRadians, jumpIfFar);
     
     if(interiorId != m_interiorSelectionModel.GetSelectedInteriorId() && interiorId != Eegeo::Resources::Interiors::InteriorId::NullId())
     {
         EnqueueTransitionToInteriorStage(newInterestPoint, distanceFromInterest, interiorId, targetFloorIndex);
     }
     
     StartQueuedTransition();
 }