About the Globe Fly tool Sample
[C#]
Fly.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
using ESRI.ArcGIS.Analyst3D;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.GlobeCore;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
namespace GlobeFlyTool
{
public class Fly : ESRI.ArcGIS.Desktop.AddIns.Tool
{
#region DllImport
[DllImport("user32")]
public static extern int SetCursor(int hCursor);
[DllImport("user32")]
public static extern int GetClientRect(int hwnd, ref Rectangle lpRect);
[DllImport("user32")]
static extern bool GetCursorPos(ref System.Drawing.Point lpPoint);
[DllImport("user32")]
public static extern int GetWindowRect(int hwnd, ref Rectangle lpRect);
#endregion
#region Member Variables
private IGlobe globe;
private IGlobeDisplay globeDisplay;
private IGlobeCamera globeCamera;
private ICamera camera;
private IScene scene;
private bool inUse;
bool bCancel = false;
bool orbitalFly = false;
private long mouseX;
private long mouseY;
private double motion = 2; //speed of the scene fly through in scene units
private double distance; //distance between target and observer
private double currentElevation; //normal fly angles in radians
private double currentAzimut; //normal fly angles in radians
private int speed;
private System.Windows.Forms.Cursor flyCur;
private System.Windows.Forms.Cursor moveFlyCur;
private Microsoft.VisualBasic.Devices.Clock theClock;
private long lastClock;
GlobeFlyTool.PointZ observer;
GlobeFlyTool.PointZ target;
GlobeFlyTool.PointZ viewVec;
#endregion
#region Constructor/Destructor
public Fly()
{
globe = ArcGlobe.Globe;
scene = globe as IScene;
globeDisplay = globe.GlobeDisplay;
camera = globeDisplay.ActiveViewer.Camera;
globeCamera = camera as IGlobeCamera;
theClock = new Microsoft.VisualBasic.Devices.Clock();
flyCur = new System.Windows.Forms.Cursor(GetType().Assembly.GetManifestResourceStream("GlobeFlyTool.Fly.cur"));
moveFlyCur = new System.Windows.Forms.Cursor(GetType().Assembly.GetManifestResourceStream("GlobeFlyTool.fly1.cur"));
speed = 0;
}
~Fly()
{
flyCur = null;
moveFlyCur = null;
}
#endregion
protected override void OnUpdate()
{
Enabled = ArcGlobe.Application != null;
if (inUse)
Cursor = moveFlyCur;
else
Cursor = flyCur;
}
#region Tool overrides
protected override void OnMouseUp(ESRI.ArcGIS.Desktop.AddIns.Tool.MouseEventArgs arg)
{
if (arg.Button == MouseButtons.Left || arg.Button == MouseButtons.Right)
{
if (!inUse)
{
mouseX = arg.X;
mouseY = arg.Y;
if (speed == 0)
StartFlight(arg.X, arg.Y);
}
else
{
//Set the speed
if (arg.Button == MouseButtons.Left)
speed = speed + 1;
else if (arg.Button == MouseButtons.Right)
speed = speed - 1;
}
}
else
{
//EndFlight();
inUse = false;
bCancel = true;
}
}
protected override void OnMouseMove(ESRI.ArcGIS.Desktop.AddIns.Tool.MouseEventArgs arg)
{
if (!inUse) return;
mouseX = arg.X;
mouseY = arg.Y;
}
protected override void OnKeyUp(ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs arg)
{
if (inUse == true)
{
//Slow down the speed of the fly through
if (arg.KeyCode == Keys.Down || arg.KeyCode == Keys.Left)
motion = motion / 2;
//Speed up the speed of the fly through
else if (arg.KeyCode == Keys.Up || arg.KeyCode == Keys.Right)
motion = motion * 2;
else if (arg.KeyCode == Keys.Escape)
bCancel = true;
}
}
protected override void OnKeyDown(ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs arg)
{
if (arg.KeyCode == Keys.Escape) //ESC is pressed
{
bCancel = true;
}
}
#endregion
#region Fly Functions
public void StartFlight(double x, double y)
{
inUse = true;
globeDisplay.IsNavigating = true;
ESRI.ArcGIS.GlobeCore.esriGlobeCameraOrientationMode camOrientMode =
globeCamera.OrientationMode;
orbitalFly = (camOrientMode == ESRI.ArcGIS.GlobeCore.esriGlobeCameraOrientationMode.esriGlobeCameraOrientationLocal) ? true : false;
IPoint pObs = camera.Observer;
IPoint pTar = camera.Target;
observer = new GlobeFlyTool.PointZ(pObs.X, pObs.Y, pObs.Z);
target = new GlobeFlyTool.PointZ(pTar.X, pTar.Y, pTar.Z);
viewVec = target - observer;
distance = viewVec.Norm();
//avoid center of globe
if (target.Norm() < 0.25)
{
target = target + viewVec;
distance = distance * 2;
}
currentElevation = Math.Atan(viewVec.z / Math.Sqrt((viewVec.x * viewVec.x) + (viewVec.y + viewVec.y)));
currentAzimut = Math.Atan2(viewVec.y, viewVec.x);//2.26892;//
//Windows API call to get windows client coordinates
System.Drawing.Point pt = new System.Drawing.Point();
bool ans = GetCursorPos(ref pt);
Rectangle rect = new Rectangle();
if (GetWindowRect(globeDisplay.ActiveViewer.hWnd, ref rect) == 0) return;
mouseX = pt.X - rect.Left;
mouseY = pt.Y - rect.Top;
if (!orbitalFly)
{
globeCamera.OrientationMode = esriGlobeCameraOrientationMode.esriGlobeCameraOrientationGlobal;
}
else
{
globeCamera.OrientationMode = esriGlobeCameraOrientationMode.esriGlobeCameraOrientationLocal;
}
globeCamera.NavigationType = esriGlobeNavigationType.esriGlobeNavigationFree;
globeCamera.RollFactor = 1.0;
globeDisplay.IsNavigating = true;
globeDisplay.IsNavigating = false;
globeDisplay.IsNavigating = true;
lastClock = theClock.TickCount;
//Windows API call to set cursor
SetCursor(moveFlyCur.Handle.ToInt32());
//Continue the flight
Flight();
}
public void Flight()
{
//speed in scene units
double motionUnit = (0.000001 + Math.Abs(observer.Norm() - 1.0) / 200.0) * motion;
//Get IMessageDispatcher interface
IMessageDispatcher pMessageDispatcher;
pMessageDispatcher = new MessageDispatcherClass();
//Set the ESC key to be seen as a cancel action
pMessageDispatcher.CancelOnClick = false;
pMessageDispatcher.CancelOnEscPress = true;
bCancel = false;
do
{
//Get the elapsed time
long currentClock = theClock.TickCount;
double lastFrameDuration = (double)(currentClock - lastClock) / 1000;
lastClock = currentClock;
if (lastFrameDuration < 0.01)
lastFrameDuration = 0.01;
if (lastFrameDuration > 1)
lastFrameDuration = 0.1;
System.Diagnostics.Debug.Print(lastFrameDuration.ToString());
//Windows API call to get windows client coordinates
Rectangle rect = new Rectangle();
if (GetClientRect(globeDisplay.ActiveViewer.hWnd, ref rect) == 0) return;
//Get normal vectors
double dXMouseNormal, dYMouseNormal;
dXMouseNormal = 2 * ((double)mouseX / (double)(rect.Right - rect.Left)) - 1;
dYMouseNormal = 2 * ((double)mouseY / (double)(rect.Bottom - rect.Top)) - 1;
PointZ dir = this.RotateNormal(lastFrameDuration, dXMouseNormal, dYMouseNormal);
PointZ visTarget = new PointZ(observer.x + distance * dir.x, observer.y + distance * dir.y, observer.z + distance * dir.z);
target.x = visTarget.x;
target.y = visTarget.y;
target.z = visTarget.z;
if (speed != 0)
{
int speedFactor = (speed > 0) ? (1 << speed) : -(1 << (-speed));
//Move the camera in the viewing directions
observer.x = observer.x + (lastFrameDuration * (2 ^ speedFactor) * motionUnit * dir.x);
observer.y = observer.y + (lastFrameDuration * (2 ^ speedFactor) * motionUnit * dir.y);
observer.z = observer.z + (lastFrameDuration * (2 ^ speedFactor) * motionUnit * dir.z);
target.x = target.x + (lastFrameDuration * (2 ^ speedFactor) * motionUnit * dir.x);
target.y = target.y + (lastFrameDuration * (2 ^ speedFactor) * motionUnit * dir.y);
target.z = target.z + (lastFrameDuration * (2 ^ speedFactor) * motionUnit * dir.z);
}
ESRI.ArcGIS.GlobeCore.IGlobeViewUtil globeViewUtil = globeCamera as ESRI.ArcGIS.GlobeCore.IGlobeViewUtil;
double obsLat;
double obsLon;
double obsAlt;
double tarLat;
double tarLon;
double tarAlt;
globeViewUtil.GeocentricToGeographic(observer.x, observer.y, observer.z, out obsLon, out obsLat, out obsAlt);
globeViewUtil.GeocentricToGeographic(target.x, target.y, target.z, out tarLon, out tarLat, out tarAlt);
globeCamera.SetObserverLatLonAlt(obsLat, obsLon, obsAlt / 1000);
globeCamera.SetTargetLatLonAlt(tarLat, tarLon, tarAlt / 1000);
globeCamera.SetAccurateViewDirection(target.x - observer.x, target.y - observer.y, target.z - observer.z);
double rollAngle = 0;
if (speed > 0)
{
rollAngle = 10 * dXMouseNormal * Math.Abs(dXMouseNormal);
}
camera.RollAngle = rollAngle;
//Redraw the scene viewer
globeDisplay.RefreshViewers();
//Dispatch any waiting messages: OnMouseMove / OnMouseUp / OnKeyUp events
object objCancel = bCancel as object;
pMessageDispatcher.Dispatch(globeDisplay.ActiveViewer.hWnd, false, out objCancel);
//End flight if ESC key pressed
if (bCancel == true)
EndFlight();
}
while (inUse == true && bCancel == false);
bCancel = false;
}
public void EndFlight()
{
inUse = false;
bCancel = true;
speed = 0;
globeDisplay.IsNavigating = false;
// reposition target
PointZ currentObs = new PointZ();
IPoint newTarget = new PointClass();
currentObs.x = camera.Observer.X;
currentObs.y = camera.Observer.Y;
currentObs.z = camera.Observer.Z;
int orX = 0;
int orY = 0;
int width = 0;
int height = 0;
camera.GetViewport(ref orX, ref orY, ref width, ref height);
object obj1;
object obj2;
try
{
globeDisplay.Locate(globeDisplay.ActiveViewer, width / 2, height / 2, true, true, out newTarget, out obj1, out obj2);
}
catch (System.Exception e)
{
MessageBox.Show(e.Message);
MessageBox.Show(e.StackTrace.ToString());
}
if (newTarget == null) // no intersection with globe, but don't let the target to be too far
{
newTarget = camera.Target;
PointZ tar = new PointZ(currentObs.x, currentObs.y, currentObs.z);
double elevObs = tar.Norm() - 1.0;
if (elevObs <= 0.0001)
elevObs = 0.0001;
PointZ oldTarget = new PointZ(newTarget.X, newTarget.Y, newTarget.Z);
PointZ dir = (oldTarget - tar);
double val = dir.Norm();
if (val > 0.0)
{
dir.x = dir.x * elevObs * 10 / val;
dir.y = dir.y * elevObs * 10 / val;
dir.z = dir.z * elevObs * 10 / val;
}
tar = tar + dir;
newTarget.X = tar.x;
newTarget.Y = tar.y;
newTarget.Z = tar.z;
}
ESRI.ArcGIS.GlobeCore.IGlobeViewUtil globeViewUtil = globeCamera as ESRI.ArcGIS.GlobeCore.IGlobeViewUtil;
double obsLat;
double obsLon;
double obsAlt;
double tarLat;
double tarLon;
double tarAlt;
globeViewUtil.GeocentricToGeographic(currentObs.x, currentObs.y, currentObs.z, out obsLon, out obsLat, out obsAlt);
globeViewUtil.GeocentricToGeographic(newTarget.X, newTarget.Y, newTarget.Z, out tarLon, out tarLat, out tarAlt);
globeCamera.SetObserverLatLonAlt(obsLat, obsLon, obsAlt / 1000);
globeCamera.SetTargetLatLonAlt(tarLat, tarLon, tarAlt / 1000);
camera.RollAngle = 0;
camera.PropertiesChanged();
globeDisplay.RefreshViewers();
//Windows API call to set cursor
SetCursor(moveFlyCur.Handle.ToInt32());
}
public PointZ RotateNormal(double lastFrameDuration, double mouseXNorm, double mouseYNorm)
{
currentElevation = currentElevation - (lastFrameDuration * mouseYNorm * (Math.Abs(mouseYNorm)));
currentAzimut = currentAzimut - (lastFrameDuration * mouseXNorm * (Math.Abs(mouseXNorm)));
if (currentElevation > 0.45 * 3.141592)
{
currentElevation = 0.45 * 3.141592;
}
if (currentElevation < -0.45 * 3.141592)
{
currentElevation = -0.45 * 3.141592;
}
while (currentAzimut < 0)
{
currentAzimut = currentAzimut + (2 * 3.141592);
}
while (currentAzimut > 2 * 3.141592)
{
currentAzimut = currentAzimut - (2 * 3.141592);
}
double x = Math.Cos(currentElevation) * Math.Cos(currentAzimut);
double y = Math.Cos(currentElevation) * Math.Sin(currentAzimut);
double z = Math.Sin(currentElevation);
GlobeFlyTool.PointZ p = new PointZ(x, y, z);
return p;
}
#endregion
}
}
[Visual Basic .NET]
Fly.vb
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports System.Drawing
Imports ESRI.ArcGIS.Analyst3D
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.ADF.BaseClasses
Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.GlobeCore
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.SystemUI
Namespace GlobeFlyTool
Public Class Fly
Inherits ESRI.ArcGIS.Desktop.AddIns.Tool
#Region "DllImport"
<DllImport("user32")> _
Public Shared Function SetCursor(ByVal hCursor As Integer) As Integer
End Function
<DllImport("user32")> _
Public Shared Function GetClientRect(ByVal hwnd As Integer, ByRef lpRect As Rectangle) As Integer
End Function
<DllImport("user32")> _
Shared Function GetCursorPos(ByRef lpPoint As System.Drawing.Point) As Boolean
End Function
<DllImport("user32")> _
Public Shared Function GetWindowRect(ByVal hwnd As Integer, ByRef lpRect As Rectangle) As Integer
End Function
#End Region
#Region "Member Variables"
Private globe As IGlobe
Private globeDisplay As IGlobeDisplay
Private globeCamera As IGlobeCamera
Private camera As ICamera
Private scene As IScene
Private inUse As Boolean
Private bCancel As Boolean = False
Private orbitalFly As Boolean = False
Private mouseX As Long
Private mouseY As Long
Private motion As Double = 2 'speed of the scene fly through in scene units
Private distance As Double 'distance between target and observer
Private currentElevation As Double 'normal fly angles in radians
Private currentAzimut As Double 'normal fly angles in radians
Private speed As Integer
Private flyCur As System.Windows.Forms.Cursor
Private moveFlyCur As System.Windows.Forms.Cursor
Private theClock As Microsoft.VisualBasic.Devices.Clock
Private lastClock As Long
Private observer As GlobeFlyTool.PointZ
Private target As GlobeFlyTool.PointZ
Private viewVec As GlobeFlyTool.PointZ
#End Region
#Region "Constructor/Destructor"
Public Sub New()
globe = ArcGlobe.Globe
scene = TryCast(globe, IScene)
globeDisplay = globe.GlobeDisplay
camera = globeDisplay.ActiveViewer.Camera
globeCamera = TryCast(camera, IGlobeCamera)
theClock = New Microsoft.VisualBasic.Devices.Clock()
flyCur = New System.Windows.Forms.Cursor(Me.GetType().Assembly.GetManifestResourceStream("Fly.cur"))
moveFlyCur = New System.Windows.Forms.Cursor(Me.GetType().Assembly.GetManifestResourceStream("fly1.cur"))
speed = 0
End Sub
Protected Overrides Sub Finalize()
flyCur = Nothing
moveFlyCur = Nothing
End Sub
#End Region
Protected Overrides Sub OnUpdate()
Enabled = ArcGlobe.Application IsNot Nothing
If inUse Then
Cursor = moveFlyCur
Else
Cursor = flyCur
End If
End Sub
#Region "Tool overrides"
Protected Overrides Sub OnMouseUp(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.MouseEventArgs)
If arg.Button = MouseButtons.Left OrElse arg.Button = MouseButtons.Right Then
If (Not inUse) Then
mouseX = arg.X
mouseY = arg.Y
If speed = 0 Then
StartFlight(arg.X, arg.Y)
End If
Else
'Set the speed
If arg.Button = MouseButtons.Left Then
speed = speed + 1
ElseIf arg.Button = MouseButtons.Right Then
speed = speed - 1
End If
End If
Else
'EndFlight();
inUse = False
bCancel = True
End If
End Sub
Protected Overrides Sub OnMouseMove(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.MouseEventArgs)
If (Not inUse) Then
Return
End If
mouseX = arg.X
mouseY = arg.Y
End Sub
Protected Overrides Sub OnKeyUp(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs)
If inUse = True Then
'Slow down the speed of the fly through
If arg.KeyCode = Keys.Down OrElse arg.KeyCode = Keys.Left Then
motion = motion / 2
'Speed up the speed of the fly through
ElseIf arg.KeyCode = Keys.Up OrElse arg.KeyCode = Keys.Right Then
motion = motion * 2
ElseIf arg.KeyCode = Keys.Escape Then
bCancel = True
End If
End If
End Sub
Protected Overrides Sub OnKeyDown(ByVal arg As ESRI.ArcGIS.Desktop.AddIns.Tool.KeyEventArgs)
If arg.KeyCode = Keys.Escape Then 'ESC is pressed
bCancel = True
End If
End Sub
#End Region
#Region "Fly Functions"
Public Sub StartFlight(ByVal x As Double, ByVal y As Double)
inUse = True
globeDisplay.IsNavigating = True
Dim camOrientMode As ESRI.ArcGIS.GlobeCore.esriGlobeCameraOrientationMode = globeCamera.OrientationMode
orbitalFly = If((camOrientMode = ESRI.ArcGIS.GlobeCore.esriGlobeCameraOrientationMode.esriGlobeCameraOrientationLocal), True, False)
Dim pObs As IPoint = camera.Observer
Dim pTar As IPoint = camera.Target
observer = New GlobeFlyTool.PointZ(pObs.X, pObs.Y, pObs.Z)
target = New GlobeFlyTool.PointZ(pTar.X, pTar.Y, pTar.Z)
viewVec = target - observer
distance = viewVec.Norm()
'avoid center of globe
If target.Norm() < 0.25 Then
target = target + viewVec
distance = distance * 2
End If
currentElevation = Math.Atan(viewVec.z / Math.Sqrt((viewVec.x * viewVec.x) + (viewVec.y + viewVec.y)))
currentAzimut = Math.Atan2(viewVec.y, viewVec.x) '2.26892;//
'Windows API call to get windows client coordinates
Dim pt As New System.Drawing.Point()
Dim ans As Boolean = GetCursorPos(pt)
Dim rect As New Rectangle()
If GetWindowRect(globeDisplay.ActiveViewer.hWnd, rect) = 0 Then
Return
End If
mouseX = pt.X - rect.Left
mouseY = pt.Y - rect.Top
If (Not orbitalFly) Then
globeCamera.OrientationMode = esriGlobeCameraOrientationMode.esriGlobeCameraOrientationGlobal
Else
globeCamera.OrientationMode = esriGlobeCameraOrientationMode.esriGlobeCameraOrientationLocal
End If
globeCamera.NavigationType = esriGlobeNavigationType.esriGlobeNavigationFree
globeCamera.RollFactor = 1.0
globeDisplay.IsNavigating = True
globeDisplay.IsNavigating = False
globeDisplay.IsNavigating = True
lastClock = theClock.TickCount
'Windows API call to set cursor
SetCursor(moveFlyCur.Handle.ToInt32())
'Continue the flight
Flight()
End Sub
Public Sub Flight()
'speed in scene units
Dim motionUnit As Double = (0.000001 + Math.Abs(observer.Norm() - 1.0) / 200.0) * motion
'Get IMessageDispatcher interface
Dim pMessageDispatcher As IMessageDispatcher
pMessageDispatcher = New MessageDispatcherClass()
'Set the ESC key to be seen as a cancel action
pMessageDispatcher.CancelOnClick = False
pMessageDispatcher.CancelOnEscPress = True
bCancel = False
Do
'Get the elapsed time
Dim currentClock As Long = theClock.TickCount
Dim lastFrameDuration As Double = CDbl(currentClock - lastClock) / 1000
lastClock = currentClock
If lastFrameDuration < 0.01 Then
lastFrameDuration = 0.01
End If
If lastFrameDuration > 1 Then
lastFrameDuration = 0.1
End If
System.Diagnostics.Debug.Print(lastFrameDuration.ToString())
'Windows API call to get windows client coordinates
Dim rect As New Rectangle()
If GetClientRect(globeDisplay.ActiveViewer.hWnd, rect) = 0 Then
Return
End If
'Get normal vectors
Dim dXMouseNormal, dYMouseNormal As Double
dXMouseNormal = 2 * (CDbl(mouseX) / CDbl(rect.Right - rect.Left)) - 1
dYMouseNormal = 2 * (CDbl(mouseY) / CDbl(rect.Bottom - rect.Top)) - 1
Dim dir As PointZ = Me.RotateNormal(lastFrameDuration, dXMouseNormal, dYMouseNormal)
Dim visTarget As New PointZ(observer.x + distance * dir.x, observer.y + distance * dir.y, observer.z + distance * dir.z)
target.x = visTarget.x
target.y = visTarget.y
target.z = visTarget.z
If speed <> 0 Then
Dim speedFactor As Integer = If((speed > 0), (1 << speed), -(1 << (-speed)))
'Move the camera in the viewing directions
observer.x = observer.x + (lastFrameDuration * (2 Xor speedFactor) * motionUnit * dir.x)
observer.y = observer.y + (lastFrameDuration * (2 Xor speedFactor) * motionUnit * dir.y)
observer.z = observer.z + (lastFrameDuration * (2 Xor speedFactor) * motionUnit * dir.z)
target.x = target.x + (lastFrameDuration * (2 Xor speedFactor) * motionUnit * dir.x)
target.y = target.y + (lastFrameDuration * (2 Xor speedFactor) * motionUnit * dir.y)
target.z = target.z + (lastFrameDuration * (2 Xor speedFactor) * motionUnit * dir.z)
End If
Dim globeViewUtil As ESRI.ArcGIS.GlobeCore.IGlobeViewUtil = TryCast(globeCamera, ESRI.ArcGIS.GlobeCore.IGlobeViewUtil)
Dim obsLat As Double
Dim obsLon As Double
Dim obsAlt As Double
Dim tarLat As Double
Dim tarLon As Double
Dim tarAlt As Double
globeViewUtil.GeocentricToGeographic(observer.x, observer.y, observer.z, obsLon, obsLat, obsAlt)
globeViewUtil.GeocentricToGeographic(target.x, target.y, target.z, tarLon, tarLat, tarAlt)
globeCamera.SetObserverLatLonAlt(obsLat, obsLon, obsAlt / 1000)
globeCamera.SetTargetLatLonAlt(tarLat, tarLon, tarAlt / 1000)
globeCamera.SetAccurateViewDirection(target.x - observer.x, target.y - observer.y, target.z - observer.z)
Dim rollAngle As Double = 0
If speed > 0 Then
rollAngle = 10 * dXMouseNormal * Math.Abs(dXMouseNormal)
End If
camera.RollAngle = rollAngle
'Redraw the scene viewer
globeDisplay.RefreshViewers()
'Dispatch any waiting messages: OnMouseMove / OnMouseUp / OnKeyUp events
Dim objCancel As Object = TryCast(bCancel, Object)
pMessageDispatcher.Dispatch(globeDisplay.ActiveViewer.hWnd, False, objCancel)
'End flight if ESC key pressed
If bCancel = True Then
EndFlight()
End If
Loop While inUse = True AndAlso bCancel = False
bCancel = False
End Sub
Public Sub EndFlight()
inUse = False
bCancel = True
speed = 0
globeDisplay.IsNavigating = False
' reposition target
Dim currentObs As New PointZ()
Dim newTarget As IPoint = New PointClass()
currentObs.x = camera.Observer.X
currentObs.y = camera.Observer.Y
currentObs.z = camera.Observer.Z
Dim orX As Integer = 0
Dim orY As Integer = 0
Dim width As Integer = 0
Dim height As Integer = 0
camera.GetViewport(orX, orY, width, height)
Dim obj1 As Object
Dim obj2 As Object
Try
globeDisplay.Locate(globeDisplay.ActiveViewer, width \ 2, height \ 2, True, True, newTarget, obj1, obj2)
Catch e As System.Exception
MessageBox.Show(e.Message)
MessageBox.Show(e.StackTrace.ToString())
End Try
If newTarget Is Nothing Then ' no intersection with globe, but don't let the target to be too far
newTarget = camera.Target
Dim tar As New PointZ(currentObs.x, currentObs.y, currentObs.z)
Dim elevObs As Double = tar.Norm() - 1.0
If elevObs <= 0.0001 Then
elevObs = 0.0001
End If
Dim oldTarget As New PointZ(newTarget.X, newTarget.Y, newTarget.Z)
Dim dir As PointZ = (oldTarget - tar)
Dim val As Double = dir.Norm()
If val > 0.0 Then
dir.x = dir.x * elevObs * 10 / val
dir.y = dir.y * elevObs * 10 / val
dir.z = dir.z * elevObs * 10 / val
End If
tar = tar + dir
newTarget.X = tar.x
newTarget.Y = tar.y
newTarget.Z = tar.z
End If
Dim globeViewUtil As ESRI.ArcGIS.GlobeCore.IGlobeViewUtil = TryCast(globeCamera, ESRI.ArcGIS.GlobeCore.IGlobeViewUtil)
Dim obsLat As Double
Dim obsLon As Double
Dim obsAlt As Double
Dim tarLat As Double
Dim tarLon As Double
Dim tarAlt As Double
globeViewUtil.GeocentricToGeographic(currentObs.x, currentObs.y, currentObs.z, obsLon, obsLat, obsAlt)
globeViewUtil.GeocentricToGeographic(newTarget.X, newTarget.Y, newTarget.Z, tarLon, tarLat, tarAlt)
globeCamera.SetObserverLatLonAlt(obsLat, obsLon, obsAlt / 1000)
globeCamera.SetTargetLatLonAlt(tarLat, tarLon, tarAlt / 1000)
camera.RollAngle = 0
camera.PropertiesChanged()
globeDisplay.RefreshViewers()
'Windows API call to set cursor
SetCursor(moveFlyCur.Handle.ToInt32())
End Sub
Public Function RotateNormal(ByVal lastFrameDuration As Double, ByVal mouseXNorm As Double, ByVal mouseYNorm As Double) As PointZ
currentElevation = currentElevation - (lastFrameDuration * mouseYNorm * (Math.Abs(mouseYNorm)))
currentAzimut = currentAzimut - (lastFrameDuration * mouseXNorm * (Math.Abs(mouseXNorm)))
If currentElevation > 0.45 * 3.141592 Then
currentElevation = 0.45 * 3.141592
End If
If currentElevation < -0.45 * 3.141592 Then
currentElevation = -0.45 * 3.141592
End If
Do While currentAzimut < 0
currentAzimut = currentAzimut + (2 * 3.141592)
Loop
Do While currentAzimut > 2 * 3.141592
currentAzimut = currentAzimut - (2 * 3.141592)
Loop
Dim x As Double = Math.Cos(currentElevation) * Math.Cos(currentAzimut)
Dim y As Double = Math.Cos(currentElevation) * Math.Sin(currentAzimut)
Dim z As Double = Math.Sin(currentElevation)
Dim p As GlobeFlyTool.PointZ = New PointZ(x, y, z)
Return p
End Function
#End Region
End Class
End Namespace