ArcObjects Library Reference  

VisualizeCameraPath

About the Visualizing the camera path while animating Sample

[C#]

VisualizeCameraPath.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.GlobeCore;
using ESRI.ArcGIS.Animation;
using ESRI.ArcGIS.Analyst3D;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.DataSourcesGDB;


namespace VisualizeCameraPath
{
    public class VisualizeCameraPath : ESRI.ArcGIS.Desktop.AddIns.Button
    {

        #region Member Variables

        private ESRI.ArcGIS.GlobeCore.IGlobe globe;
        private ESRI.ArcGIS.GlobeCore.IGlobeDisplay globeDisplay;
        private ESRI.ArcGIS.Carto.IGraphicsContainer graphicsLayer;
        private ESRI.ArcGIS.GlobeCore.IGlobeCamera globeCamera;
        private ESRI.ArcGIS.Animation.IAGAnimationTracks animationTracks;
        private ESRI.ArcGIS.Animation.IAGAnimationTrack animationTrack;
        private VisualizeCameraPathForm theCamForm;
        private ESRI.ArcGIS.Animation.IAGAnimationUtils animUtils;
        private ESRI.ArcGIS.Animation.IAnimationEvents_Event animEvent;
        private ESRI.ArcGIS.Animation.IAGAnimationEnvironment animEnv;
        private ESRI.ArcGIS.Animation.IAGAnimationPlayer animPlayer;
        private ESRI.ArcGIS.GlobeCore.IGlobeDisplayEvents_Event globeDispEvent;
        private bool toolIsInitialized = false;
        private double animationDuration = 0;

        #endregion

        #region DLLImportFunction

        [DllImport("gdi32.dll")]
        static extern bool DeleteObject(IntPtr hObject);

        [DllImport("user32.dll")]
        static extern int ShowWindow(int hwnd, int nCmdShow);


        #endregion

        public VisualizeCameraPath()
        {
            globe = ArcGlobe.Globe;
            globeDisplay = globe.GlobeDisplay;
            globeCamera = globeDisplay.ActiveViewer.Camera as IGlobeCamera;
        }


        ~VisualizeCameraPath()
        {
            if (theCamForm != null)
            {
                theCamForm.Dispose();
            }
        }

        protected override void OnClick()
        {
            //The first time button is clicked
			if(toolIsInitialized == false)
			{
				theCamForm = new VisualizeCameraPathForm();
			
				//Add event handlers for form's button click events
				theCamForm.playButton.Click+= new System.EventHandler(formPlayButtonClickEventHandler);
				theCamForm.stopButton.Click+= new System.EventHandler(formStopButtonClickEventHandler);
				theCamForm.generatePathButton.Click+= new System.EventHandler(formGeneratePathButtonClickEventHandler);
	
				theCamForm.generateCamPathCheckBox.CheckedChanged += new EventHandler(formCheckbox1CheckedChanged);

				theCamForm.Closing += new CancelEventHandler(theCamForm_Closing);

				animEnv = new AGAnimationEnvironmentClass();

				//True = Button has been already clicked
				toolIsInitialized = true;
            }
            //If the main form is already open - do not open another one
            else if (toolIsInitialized == true)
            {
                //Clear the list of animation tracks
                theCamForm.animTracksListBox.Items.Clear();
            }
            //Get the list of animation tracks
            this.getCameraAnimationTracksFromGlobe();
            theCamForm.Show();

        }

        protected override void OnUpdate()
        {
            Enabled = ArcGlobe.Application != null;
        }


        #region Custom Functions and Event Handlers

        //function for getting camera animation tracks
        public void getCameraAnimationTracksFromGlobe()
        {
            ESRI.ArcGIS.Animation.IAGAnimationType animationType = new AnimationTypeGlobeCameraClass();
            animationTracks = (ESRI.ArcGIS.Animation.IAGAnimationTracks)globe;
            int animCounter = 0;
            while (animCounter < animationTracks.AGTracks.Count)
            {
                animationTrack = (ESRI.ArcGIS.Animation.IAGAnimationTrack)animationTracks.AGTracks.get_Element(animCounter);
                if (animationTrack.AnimationType == animationType)
                {
                    theCamForm.animTracksListBox.Items.Add(animationTrack.Name);
                }
                animCounter = animCounter + 1;
            }
        }

        //function for enabling selected animation track
        public void enableSelectedTrack()
        {
            if (theCamForm.animTracksListBox.SelectedItem != null)
            {
                string selectedTrack = theCamForm.animTracksListBox.SelectedItem.ToString();
                int animCounter = 0;
                while (animCounter < animationTracks.AGTracks.Count)
                {
                    animationTrack = (IAGAnimationTrack)animationTracks.AGTracks.get_Element(animCounter);
                    if (animationTrack.Name != selectedTrack)
                    {
                        IAGAnimationTrack trackToDisable;
                        animationTracks.FindTrack(animationTrack.Name, out trackToDisable);
                        trackToDisable.IsEnabled = false;
                    }
                    else if (animationTrack.Name == selectedTrack)
                    {
                        animationTrack.IsEnabled = true;
                    }
                    animCounter = animCounter + 1;
                }
            }

            else if (theCamForm.animTracksListBox.SelectedItem == null)
            {
                MessageBox.Show("No Track Selected - All enabled tracks will be played");
            }
        }

        //function for playing animation
        public void playAnimation()
        {
            animUtils = new AGAnimationUtilsClass();
            //register/unregister events for tracing camera path based on selection
            animEvent = (IAnimationEvents_Event)animUtils;

            //set animation duration
            if (theCamForm.animDurationTextBox.Text != "" & theCamForm.animDurationTextBox.Text != "Optional")
            {
                animEnv.AnimationDuration = Convert.ToDouble(theCamForm.animDurationTextBox.Text);
            }
            else
            {
                MessageBox.Show("Please enter animation duration", "Error");
                return;
            }

            //register animation event handler
            animEvent.StateChanged += new IAnimationEvents_StateChangedEventHandler(myAnimationEventHandler);

            //enable/disable other buttons
            theCamForm.stopButton.Enabled = true;
            theCamForm.generatePathButton.Enabled = false;
            theCamForm.playButton.Enabled = false;

            animPlayer = (IAGAnimationPlayer)animUtils;

            animationDuration = animEnv.AnimationDuration;

            animPlayer.PlayAnimation(animationTracks, animEnv, null);
        }

        //function for creating specified number of graphics per second
        public void generatePathPerSecond()
        {
            //set animation duration
            if (theCamForm.animDurationTextBox.Text != "" & theCamForm.animDurationTextBox.Text != "Optional")
            {
                animEnv.AnimationDuration = Convert.ToDouble(theCamForm.animDurationTextBox.Text);
            }
            else
            {
                MessageBox.Show("Please enter animation duration", "Error");
                return;
            }
            animationDuration = animEnv.AnimationDuration;

            int numPtsPerSecond = 0;
            if (theCamForm.numPtsPerSecTextBox.Text != "")
            {
                numPtsPerSecond = Convert.ToInt32(theCamForm.numPtsPerSecTextBox.Text);
            }

            addGraphicLayer();

            string selectedTrack = theCamForm.animTracksListBox.SelectedItem.ToString();

            animationTracks.FindTrack(selectedTrack, out animationTrack);

            IAGAnimationTrackKeyframes kFrames = (IAGAnimationTrackKeyframes)animationTrack;

            int kFrameCount = kFrames.KeyframeCount;

            //total number of points to be created
            int totalPts = (int)(numPtsPerSecond * animationDuration);

            //this is the from point for the lines connecting the interpolated point graphics
            IPoint previousPt = new PointClass();
            IZAware prevPtZAware = (IZAware)previousPt;
            prevPtZAware.ZAware = true;
            previousPt.PutCoords(0, 0);

            //this is the line connecting the interpolated camera positions
            IPolyline connectingLine = new PolylineClass();
            IZAware lineZAware = (IZAware)connectingLine;
            lineZAware.ZAware = true;

            //disable all buttons
            theCamForm.playButton.Enabled = false;
            theCamForm.stopButton.Enabled = false;
            theCamForm.generatePathButton.Enabled = false;

            //loop over the keyframes in the selected camera track
            for (int i = 0; i < kFrameCount; i++)
            {
                IAGKeyframe currentKeyframe = kFrames.get_Keyframe(i);
                IAGKeyframe prevKeyframe;
                IAGKeyframe nextKeyframe;
                IAGKeyframe afterNextKeyframe;

                //if else statements to determine the keyframe arguments to the interpolate method
                //this is needed because the first, second-last and the last keyframes should be handled differently
                //than the middle keyframes
                if (i > 0)
                {
                    prevKeyframe = kFrames.get_Keyframe(i - 1);
                }

                else
                {
                    prevKeyframe = kFrames.get_Keyframe(i);
                }

                if (i < kFrameCount - 1)
                {
                    nextKeyframe = kFrames.get_Keyframe(i + 1);
                }
                else
                {
                    nextKeyframe = kFrames.get_Keyframe(i);
                }

                if (i < kFrameCount - 2)
                {
                    afterNextKeyframe = kFrames.get_Keyframe(i + 2);
                }
                else
                {
                    //this should be equal to the nextKeyFrame for the last keyframe
                    afterNextKeyframe = nextKeyframe;//kFrames.get_Keyframe(i); 
                }

                double origCamLat, origCamLong, origCamAlt;
                double interLat, interLong, interAlt;
                double tarLat, tarLong, tarAlt;
                double interTarLat, interTarLong, interTarAlt;

                globeCamera.GetObserverLatLonAlt(out origCamLat, out origCamLong, out origCamAlt);
                globeCamera.GetTargetLatLonAlt(out tarLat, out tarLong, out tarAlt);

                IAGAnimationContainer pAnimContainer = animationTracks.AnimationObjectContainer;

                object objToInterpolate = (object)globeCamera;

                double timeDiff = nextKeyframe.TimeStamp - currentKeyframe.TimeStamp;

                int numPtsToInterpolateNow;
                numPtsToInterpolateNow = Convert.ToInt32((timeDiff * totalPts));

                //interpolate positions between keyframes and draw the graphics

                //for 0 to n-1 keyframes
                if (i < kFrameCount - 1)
                {
                    for (int j = 0; j < numPtsToInterpolateNow; j++)
                    {
                        double timeToInterpolate;
                        timeToInterpolate = currentKeyframe.TimeStamp + j * (timeDiff / (numPtsToInterpolateNow));

                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);

                        //get observer and target lat, long, alt after interpolation
                        globeCamera.GetObserverLatLonAlt(out interLat, out interLong, out interAlt);
                        globeCamera.GetTargetLatLonAlt(out interTarLat, out interTarLong, out interTarAlt);

                        //set observer and target lat, long, alt to original values before interpolation
                        globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt);
                        globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt);

                        IPoint pObs = new PointClass();
                        IZAware obsZAware = (IZAware)pObs;
                        obsZAware.ZAware = true;
                        pObs.X = interLong;
                        pObs.Y = interLat;
                        pObs.Z = interAlt * 1000;

                        double symbolSize = 10000;

                        //change the symbol size based on distance to ground
                        if (pObs.Z >= 10000) symbolSize = 10000 + pObs.Z / 10;
                        else symbolSize = pObs.Z;

                        //add graphics - keyframes (j=0) are colored differently
                        if (j == 0) addPointGraphicElements(pObs, 2552550, symbolSize);
                        else addPointGraphicElements(pObs, 16732415, symbolSize);

                        connectingLine.FromPoint = previousPt;
                        connectingLine.ToPoint = pObs;

                        //barring the first keyframe, create the line connecting the interpolated points
                        if (i == 0 & j == 0) { }
                        else
                        {
                            addLineGraphicElements(connectingLine, 150150150);
                        }

                        //update the previous point
                        previousPt.PutCoords(pObs.X, pObs.Y);
                        previousPt.Z = pObs.Z;

                        //add camera to target direction
                        if (theCamForm.camToTargetDirectionCheckBox.Checked == true)
                        {
                            cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt);
                        }

                        globeDisplay.RefreshViewers();
                    }
                }

                //for last keyframe
                if (i == kFrameCount - 1)
                {
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);

                    globeCamera.GetObserverLatLonAlt(out interLat, out interLong, out interAlt);
                    globeCamera.GetTargetLatLonAlt(out interTarLat, out interTarLong, out interTarAlt);

                    globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt);
                    globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt);

                    IPoint pObs = new PointClass();
                    IZAware obsZAware = (IZAware)pObs;
                    obsZAware.ZAware = true;
                    pObs.X = interLong;
                    pObs.Y = interLat;
                    pObs.Z = interAlt * 1000;

                    double symbolSize = 10000;

                    if (pObs.Z >= 10000) symbolSize = 10000 + pObs.Z / 10;
                    else symbolSize = pObs.Z;

                    connectingLine.FromPoint = previousPt;
                    connectingLine.ToPoint = pObs;

                    addPointGraphicElements(pObs, 2552550, symbolSize);
                    addLineGraphicElements(connectingLine, 150150150);

                    //add camera to target orientation
                    if (theCamForm.camToTargetDirectionCheckBox.Checked == true)
                    {
                        cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt);
                    }

                    globeDisplay.RefreshViewers();
                }
            }

            //enable buttons
            theCamForm.playButton.Enabled = true;
            theCamForm.generatePathButton.Enabled = true;
        }

        //function for creating specified number of graphics between keyframe positions
        public void generatePathBtwnKFrames()
        {
            int numPtsBtwnKFrames = 0;

            //this is the from point for the lines connecting the interpolated point graphics
            IPoint previousPt = new PointClass();
            IZAware prevPtZAware = (IZAware)previousPt;
            prevPtZAware.ZAware = true;
            previousPt.PutCoords(0, 0);

            //this is the line connecting the interpolated camera positions
            IPolyline connectingLine = new PolylineClass();
            IZAware lineZAware = (IZAware)connectingLine;
            lineZAware.ZAware = true;

            if (theCamForm.ptsBtwnKframeTextBox.Text != "")
            {
                numPtsBtwnKFrames = Convert.ToInt32(theCamForm.ptsBtwnKframeTextBox.Text);
            }
            else
            {
                MessageBox.Show("Please enter the number of points to be created");
                return;
            }
            theCamForm.playButton.Enabled = false;
            theCamForm.stopButton.Enabled = false;
            theCamForm.generatePathButton.Enabled = false;

            addGraphicLayer();

            string selectedTrack = theCamForm.animTracksListBox.SelectedItem.ToString();

            animationTracks.FindTrack(selectedTrack, out animationTrack);

            IAGAnimationTrackKeyframes kFrames = (IAGAnimationTrackKeyframes)animationTrack;

            int kFrameCount = kFrames.KeyframeCount;

            //loop over the keyframes in the selected camera track
            for (int i = 0; i < kFrameCount; i++)
            {
                IAGKeyframe currentKeyframe = kFrames.get_Keyframe(i);
                IAGKeyframe prevKeyframe;
                IAGKeyframe nextKeyframe;
                IAGKeyframe afterNextKeyframe;

                //if else statements to determine the keyframe arguments to the interpolate method
                //this is needed because the first and the last keyframes should be handled differently
                //than the middle keyframes
                if (i > 0)
                {
                    prevKeyframe = kFrames.get_Keyframe(i - 1);
                }

                else
                {
                    prevKeyframe = kFrames.get_Keyframe(i);
                }

                if (i < kFrameCount - 1)
                {
                    nextKeyframe = kFrames.get_Keyframe(i + 1);
                }
                else
                {
                    nextKeyframe = kFrames.get_Keyframe(i);
                }

                if (i < kFrameCount - 2)
                {
                    afterNextKeyframe = kFrames.get_Keyframe(i + 2);
                }
                else
                {
                    //this should be equal to the nextKeyFrame for the last keyframe
                    afterNextKeyframe = nextKeyframe;//kFrames.get_Keyframe(i); 
                }

                double origCamLat, origCamLong, origCamAlt;
                double interLat, interLong, interAlt;
                double tarLat, tarLong, tarAlt;
                double interTarLat, interTarLong, interTarAlt;

                globeCamera.GetObserverLatLonAlt(out origCamLat, out origCamLong, out origCamAlt);
                globeCamera.GetTargetLatLonAlt(out tarLat, out tarLong, out tarAlt);


                IAGAnimationContainer pAnimContainer = animationTracks.AnimationObjectContainer;

                object objToInterpolate = (object)globeCamera;

                double timeDiff = nextKeyframe.TimeStamp - currentKeyframe.TimeStamp;

                //interpolate positions between keyframes and draw the graphics
                for (int j = 0; j < numPtsBtwnKFrames + 1; j++)
                {
                    double timeToInterpolate = currentKeyframe.TimeStamp + j * (timeDiff / (numPtsBtwnKFrames + 1));

                    //for 0 to n-1 keyframes
                    if (i >= 0 & i < kFrameCount - 1)
                    {
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe);

                        globeCamera.GetObserverLatLonAlt(out interLat, out interLong, out interAlt);
                        globeCamera.GetTargetLatLonAlt(out interTarLat, out interTarLong, out interTarAlt);

                        globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt);
                        globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt);

                        IPoint pObs = new PointClass();
                        IZAware obsZAware = (IZAware)pObs;
                        obsZAware.ZAware = true;
                        pObs.X = interLong;
                        pObs.Y = interLat;
                        pObs.Z = interAlt * 1000;

                        double symbolSize = 10000;

                        if (pObs.Z >= 10000) symbolSize = 10000 + pObs.Z / 10;
                        else symbolSize = pObs.Z;

                        if (j == 0) addPointGraphicElements(pObs, 2552550, symbolSize);
                        else addPointGraphicElements(pObs, 16732415, symbolSize);

                        connectingLine.FromPoint = previousPt;
                        connectingLine.ToPoint = pObs;

                        if (i == 0 & j == 0) { }
                        else
                        {
                            addLineGraphicElements(connectingLine, 150150150);
                        }

                        previousPt.PutCoords(pObs.X, pObs.Y);
                        previousPt.Z = pObs.Z;

                        //add camera to target orientation
                        if (theCamForm.camToTargetDirectionCheckBox.Checked == true)
                        {
                            cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt);
                        }

                        globeDisplay.RefreshViewers();
                    }

                    //for last keyframe
                    else if (i == kFrameCount - 1)
                    {
                        if (j == 0)
                        {
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, 1, nextKeyframe, prevKeyframe, afterNextKeyframe);

                            globeCamera.GetObserverLatLonAlt(out interLat, out interLong, out interAlt);
                            globeCamera.GetTargetLatLonAlt(out interTarLat, out interTarLong, out interTarAlt);

                            globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt);
                            globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt);

                            IPoint pObs = new PointClass();
                            IZAware obsZAware = (IZAware)pObs;
                            obsZAware.ZAware = true;
                            pObs.X = interLong;
                            pObs.Y = interLat;
                            pObs.Z = interAlt * 1000;

                            double symbolSize = 10000;

                            if (pObs.Z >= 10000) symbolSize = 10000 + pObs.Z / 10;
                            else symbolSize = pObs.Z;

                            connectingLine.FromPoint = previousPt;
                            connectingLine.ToPoint = pObs;

                            addPointGraphicElements(pObs, 2552550, symbolSize);
                            addLineGraphicElements(connectingLine, 150150150);

                            //add camera to target orientation
                            if (theCamForm.camToTargetDirectionCheckBox.Checked == true)
                            {
                                cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt);
                            }

                            globeDisplay.RefreshViewers();
                        }
                    }
                }
            }

            //enable buttons
            theCamForm.playButton.Enabled = true;
            theCamForm.generatePathButton.Enabled = true;
        }

        //function for generating camera to target direction
        public void cameraToTargetDirection(double camLat, double camLong, double camAlt, double tarLat, double tarLong, double tarAlt)
        {
            IPoint camPosition = new PointClass();
            IPoint targetPosition = new PointClass();

            ICamera pCamera = (ICamera)globeCamera;

            IZAware obsZAware = (IZAware)camPosition;
            obsZAware.ZAware = true;

            camPosition.PutCoords(camLong, camLat);
            camPosition.Z = camAlt * 1000;

            IZAware targetZAware = (IZAware)targetPosition;
            targetZAware.ZAware = true;

            targetPosition.PutCoords(tarLong, tarLat);
            targetPosition.Z = tarAlt;

            IPolyline directionLine = new PolylineClass();
            IZAware zAwareLine = (IZAware)directionLine;
            zAwareLine.ZAware = true;

            directionLine.FromPoint = camPosition;
            directionLine.ToPoint = targetPosition;


            addLineGraphicElements(directionLine, 255);

        }

        //function for adding a graphics layer
        public void addGraphicLayer()
        {
            graphicsLayer = new GlobeGraphicsLayerClass();
            ILayer pLayer;
            pLayer = (ILayer)graphicsLayer;
            pLayer.Name = "CameraPathGraphicsLayer";
            globe.AddLayerType(pLayer, esriGlobeLayerType.esriGlobeLayerTypeDraped, true);
        }

        //function for adding point markers
        public void addPointGraphicElements(ESRI.ArcGIS.Geometry.IPoint inPoint, int symbolColor, double symbolSize)
        {
            IElement pElement = new MarkerElementClass();
            ISimpleMarker3DSymbol symbol3d = new SimpleMarker3DSymbolClass();

            string markerStyle = "";

            if (theCamForm.symbolTypeListBox.SelectedItem != null)
            {
                markerStyle = theCamForm.symbolTypeListBox.SelectedItem.ToString();
            }

            if (markerStyle == "Cone") symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCone;
            else if (markerStyle == "Sphere") symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSSphere;
            else if (markerStyle == "Cylinder") symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCylinder;
            else if (markerStyle == "Cube") symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCube;
            else if (markerStyle == "Diamond") symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSDiamond;
            else if (markerStyle == "Tetrahedron") symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSTetra;
            else symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCone;

            symbol3d.ResolutionQuality = 1;
            IColor pColor = new RgbColorClass();
            pColor.RGB = symbolColor; //16732415;

            IMarkerSymbol pMarkerSymbol;
            pMarkerSymbol = (IMarkerSymbol)symbol3d;
            pMarkerSymbol.Color = pColor;

            if (symbolSize < 0) symbolSize = Math.Abs(symbolSize);
            if (symbolSize == 0) symbolSize = 5000;
            pMarkerSymbol.Size = symbolSize;

            pElement.Geometry = inPoint;
            IMarkerElement pMarkerElement;
            pMarkerElement = (IMarkerElement)pElement;
            pMarkerElement.Symbol = pMarkerSymbol;

            graphicsLayer.AddElement(pElement, 1);

        }

        //function for adding line graphics elements
        public void addLineGraphicElements(ESRI.ArcGIS.Geometry.IPolyline inLine, int symbolColor)
        {
            IElement pElement = new LineElementClass();// MarkerElementClass();
            ISimpleLine3DSymbol symbol3d = new SimpleLine3DSymbolClass();

            string markerStyle = "";

            if (theCamForm.symbolTypeListBox.SelectedItem != null)
            {
                markerStyle = theCamForm.symbolTypeListBox.SelectedItem.ToString();
            }

            if (markerStyle == "Strip") symbol3d.Style = esriSimple3DLineStyle.esriS3DLSStrip;
            else if (markerStyle == "Wall") symbol3d.Style = esriSimple3DLineStyle.esriS3DLSWall;
            else symbol3d.Style = esriSimple3DLineStyle.esriS3DLSTube;

            symbol3d.ResolutionQuality = 1;
            IColor pColor = new RgbColorClass();
            pColor.RGB = symbolColor;

            ILineSymbol pLineSymbol;
            pLineSymbol = (ILineSymbol)symbol3d;
            pLineSymbol.Color = pColor;
            pLineSymbol.Width = 1;

            pElement.Geometry = inLine;
            ILineElement pLineElement;
            pLineElement = (ILineElement)pElement;
            pLineElement.Symbol = pLineSymbol;

            graphicsLayer.AddElement(pElement, 1);
        }


        //event handlers
        public void formPlayButtonClickEventHandler(object sender, System.EventArgs e)
        {
            if (theCamForm.animTracksListBox.SelectedItem != null)
            {
                enableSelectedTrack();
                //play the animation
                this.playAnimation();
            }
            else
            {
                MessageBox.Show("Please select a camera track", "Error");
            }
        }

        public void formStopButtonClickEventHandler(object sender, System.EventArgs e)
        {
            animPlayer.StopAnimation();
            theCamForm.stopButton.Enabled = false;
            if (theCamForm.generateCamPathCheckBox.Checked == true) theCamForm.generatePathButton.Enabled = true;
        }

        public void formGeneratePathButtonClickEventHandler(object sender, System.EventArgs e)
        {
            if (theCamForm.animTracksListBox.SelectedItem != null)
            {
                if (theCamForm.ptsPerSecRadioButton.Checked == true)
                {
                    if (theCamForm.numPtsPerSecTextBox.Text == "")
                    {
                        MessageBox.Show("Please enter number of points to be created per second", "Error");
                        return;
                    }
                    generatePathPerSecond();
                }
                else if (theCamForm.ptsBtwnKframeRadioButton.Checked == true)
                {
                    if (theCamForm.ptsBtwnKframeTextBox.Text == "")
                    {
                        MessageBox.Show("Please enter number of points to be created between keyframes", "Error");
                        return;
                    }
                    generatePathBtwnKFrames();
                }
            }
            else
            {
                MessageBox.Show("Please select a camera track");
            }
        }

        public void formCheckbox1CheckedChanged(object sender, System.EventArgs e)
        {
            if (theCamForm.generateCamPathCheckBox.Checked == true) theCamForm.generatePathButton.Enabled = true;
            else theCamForm.generatePathButton.Enabled = false;
        }

        private void theCamForm_Closing(object sender, CancelEventArgs e)
        {
            theCamForm.animTracksListBox.Items.Clear();
            toolIsInitialized = false;
        }

        public void myAnimationEventHandler(esriAnimationState animState)
        {
            globeDispEvent = (IGlobeDisplayEvents_Event)globeDisplay;

            if (animState == esriAnimationState.esriAnimationStopped)
            {
                theCamForm.playButton.Enabled = true;
                theCamForm.generatePathButton.Enabled = true;
                theCamForm.stopButton.Enabled = false;
            }
        }

        #endregion		

    }
}

[Visual Basic .NET]

VisualizeCameraPath.vb

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.ADF.BaseClasses
Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.GlobeCore
Imports ESRI.ArcGIS.Animation
Imports ESRI.ArcGIS.Analyst3D
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.Controls
Imports ESRI.ArcGIS.DataSourcesGDB

Namespace VisualizeCameraPath
  Public Class VisualizeCameraPath : Inherits ESRI.ArcGIS.Desktop.AddIns.Button

#Region "Member Variables"

    Private globe As ESRI.ArcGIS.GlobeCore.IGlobe
    Private globeDisplay As ESRI.ArcGIS.GlobeCore.IGlobeDisplay
    Private graphicsLayer As ESRI.ArcGIS.Carto.IGraphicsContainer
    Private globeCamera As ESRI.ArcGIS.GlobeCore.IGlobeCamera
    Private animationTracks As ESRI.ArcGIS.Animation.IAGAnimationTracks
    Private animationTrack As ESRI.ArcGIS.Animation.IAGAnimationTrack
    Private theCamForm As VisualizeCameraPathForm
    Private animUtils As ESRI.ArcGIS.Animation.IAGAnimationUtils
    Private animEvent As ESRI.ArcGIS.Animation.IAnimationEvents_Event
    Private animEnv As ESRI.ArcGIS.Animation.IAGAnimationEnvironment
    Private animPlayer As ESRI.ArcGIS.Animation.IAGAnimationPlayer
    Private globeDispEvent As ESRI.ArcGIS.GlobeCore.IGlobeDisplayEvents_Event
    Private toolIsInitialized As Boolean = False
    Private animationDuration As Double = 0

#End Region

#Region "DLLImportFunction"

    <DllImport("gdi32.dll")> _
    Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll")> _
    Shared Function ShowWindow(ByVal hwnd As Integer, ByVal nCmdShow As Integer) As Integer
    End Function


#End Region

    Public Sub New()
      globe = ArcGlobe.Globe
      globeDisplay = globe.GlobeDisplay
      globeCamera = TryCast(globeDisplay.ActiveViewer.Camera, IGlobeCamera)
    End Sub


    Protected Overrides Sub Finalize()
      If Not theCamForm Is Nothing Then
        theCamForm.Dispose()
      End If
    End Sub

    Protected Overrides Sub OnClick()
      'The first time button is clicked
      If toolIsInitialized = False Then
        theCamForm = New VisualizeCameraPathForm()

        'Add event handlers for form's button click events
        AddHandler theCamForm.playButton.Click, AddressOf formPlayButtonClickEventHandler
        AddHandler theCamForm.stopButton.Click, AddressOf formStopButtonClickEventHandler
        AddHandler theCamForm.generatePathButton.Click, AddressOf formGeneratePathButtonClickEventHandler

        AddHandler theCamForm.generateCamPathCheckBox.CheckedChanged, AddressOf formCheckbox1CheckedChanged

        AddHandler theCamForm.Closing, AddressOf theCamForm_Closing

        animEnv = New AGAnimationEnvironmentClass()

        'True = Button has been already clicked
        toolIsInitialized = True
      'If the main form is already open - do not open another one
      ElseIf toolIsInitialized = True Then
        'Clear the list of animation tracks
        theCamForm.animTracksListBox.Items.Clear()
      End If
      'Get the list of animation tracks
      Me.getCameraAnimationTracksFromGlobe()
      theCamForm.Show()

    End Sub

    Protected Overrides Sub OnUpdate()
      Enabled = Not ArcGlobe.Application Is Nothing
    End Sub


#Region "Custom Functions and Event Handlers"

    'function for getting camera animation tracks
    Public Sub getCameraAnimationTracksFromGlobe()
      Dim animationType As ESRI.ArcGIS.Animation.IAGAnimationType = New AnimationTypeGlobeCameraClass()
            animationTracks = CType(globe, ESRI.ArcGIS.Animation.IAGAnimationTracks)
      Dim animCounter As Integer = 0
      Do While animCounter < animationTracks.AGTracks.Count
                animationTrack = CType(animationTracks.AGTracks.Element(animCounter), ESRI.ArcGIS.Animation.IAGAnimationTrack)
        If animationTrack.AnimationType Is animationType Then
          theCamForm.animTracksListBox.Items.Add(animationTrack.Name)
        End If
        animCounter = animCounter + 1
      Loop
    End Sub

    'function for enabling selected animation track
    Public Sub enableSelectedTrack()
      If Not theCamForm.animTracksListBox.SelectedItem Is Nothing Then
        Dim selectedTrack As String = theCamForm.animTracksListBox.SelectedItem.ToString()
        Dim animCounter As Integer = 0
        Do While animCounter < animationTracks.AGTracks.Count
                    animationTrack = CType(animationTracks.AGTracks.Element(animCounter), IAGAnimationTrack)
          If animationTrack.Name <> selectedTrack Then
                        Dim trackToDisable As IAGAnimationTrack
                        trackToDisable = Nothing
            animationTracks.FindTrack(animationTrack.Name, trackToDisable)
            trackToDisable.IsEnabled = False
          ElseIf animationTrack.Name = selectedTrack Then
            animationTrack.IsEnabled = True
          End If
          animCounter = animCounter + 1
        Loop

      ElseIf theCamForm.animTracksListBox.SelectedItem Is Nothing Then
        MessageBox.Show("No Track Selected - All enabled tracks will be played")
      End If
    End Sub

    'function for playing animation
    Public Sub playAnimation()
      animUtils = New AGAnimationUtilsClass()
      'register/unregister events for tracing camera path based on selection
      animEvent = CType(animUtils, IAnimationEvents_Event)

      'set animation duration
      If theCamForm.animDurationTextBox.Text <> "" And theCamForm.animDurationTextBox.Text <> "Optional" Then
        animEnv.AnimationDuration = Convert.ToDouble(theCamForm.animDurationTextBox.Text)
      Else
        MessageBox.Show("Please enter animation duration", "Error")
        Return
      End If

      'register animation event handler
      AddHandler animEvent.StateChanged, AddressOf myAnimationEventHandler

      'enable/disable other buttons
      theCamForm.stopButton.Enabled = True
      theCamForm.generatePathButton.Enabled = False
      theCamForm.playButton.Enabled = False

      animPlayer = CType(animUtils, IAGAnimationPlayer)

      animationDuration = animEnv.AnimationDuration

      animPlayer.PlayAnimation(animationTracks, animEnv, Nothing)
    End Sub

    'function for creating specified number of graphics per second
    Public Sub generatePathPerSecond()
      'set animation duration
      If theCamForm.animDurationTextBox.Text <> "" And theCamForm.animDurationTextBox.Text <> "Optional" Then
        animEnv.AnimationDuration = Convert.ToDouble(theCamForm.animDurationTextBox.Text)
      Else
        MessageBox.Show("Please enter animation duration", "Error")
        Return
      End If
      animationDuration = animEnv.AnimationDuration

      Dim numPtsPerSecond As Integer = 0
      If theCamForm.numPtsPerSecTextBox.Text <> "" Then
        numPtsPerSecond = Convert.ToInt32(theCamForm.numPtsPerSecTextBox.Text)
      End If

      addGraphicLayer()

      Dim selectedTrack As String = theCamForm.animTracksListBox.SelectedItem.ToString()

      animationTracks.FindTrack(selectedTrack, animationTrack)

      Dim kFrames As IAGAnimationTrackKeyframes = CType(animationTrack, IAGAnimationTrackKeyframes)

      Dim kFrameCount As Integer = kFrames.KeyframeCount

      'total number of points to be created
      Dim totalPts As Integer = CInt(numPtsPerSecond * animationDuration)

      'this is the from point for the lines connecting the interpolated point graphics
      Dim previousPt As IPoint = New PointClass()
      Dim prevPtZAware As IZAware = CType(previousPt, IZAware)
      prevPtZAware.ZAware = True
      previousPt.PutCoords(0, 0)

      'this is the line connecting the interpolated camera positions
      Dim connectingLine As IPolyline = New PolylineClass()
      Dim lineZAware As IZAware = CType(connectingLine, IZAware)
      lineZAware.ZAware = True

      'disable all buttons
      theCamForm.playButton.Enabled = False
      theCamForm.stopButton.Enabled = False
      theCamForm.generatePathButton.Enabled = False

      'loop over the keyframes in the selected camera track
      Dim i As Integer = 0
      Do While i < kFrameCount
                Dim currentKeyframe As IAGKeyframe = CType(kFrames.Keyframe(i), ESRI.ArcGIS.Animation.IAGKeyframe)
                Dim prevKeyframe As IAGKeyframe
                Dim nextKeyframe As IAGKeyframe
                Dim afterNextKeyframe As IAGKeyframe

                'if else statements to determine the keyframe arguments to the interpolate method
                'this is needed because the first, second-last and the last keyframes should be handled differently
                'than the middle keyframes
                If i > 0 Then
                    prevKeyframe = CType(kFrames.Keyframe(i - 1), ESRI.ArcGIS.Animation.IAGKeyframe)

                Else
                    prevKeyframe = CType(kFrames.Keyframe(i), ESRI.ArcGIS.Animation.IAGKeyframe)
                End If

                If i < kFrameCount - 1 Then
                    nextKeyframe = CType(kFrames.Keyframe(i + 1), ESRI.ArcGIS.Animation.IAGKeyframe)
                Else
                    nextKeyframe = CType(kFrames.Keyframe(i), ESRI.ArcGIS.Animation.IAGKeyframe)
                End If

                If i < kFrameCount - 2 Then
                    afterNextKeyframe = CType(kFrames.Keyframe(i + 2), ESRI.ArcGIS.Animation.IAGKeyframe)
                Else
                    'this should be equal to the nextKeyFrame for the last keyframe
                    afterNextKeyframe = nextKeyframe 'kFrames.Keyframe(i);
                End If

                Dim origCamLat, origCamLong, origCamAlt As Double
                Dim interLat, interLong, interAlt As Double
                Dim tarLat, tarLong, tarAlt As Double
                Dim interTarLat, interTarLong, interTarAlt As Double

                globeCamera.GetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt)
                globeCamera.GetTargetLatLonAlt(tarLat, tarLong, tarAlt)

                Dim pAnimContainer As IAGAnimationContainer = animationTracks.AnimationObjectContainer

                Dim objToInterpolate As Object = CObj(globeCamera)

                Dim timeDiff As Double = nextKeyframe.TimeStamp - currentKeyframe.TimeStamp

                Dim numPtsToInterpolateNow As Integer
                numPtsToInterpolateNow = Convert.ToInt32((timeDiff * totalPts))

                'interpolate positions between keyframes and draw the graphics

                'for 0 to n-1 keyframes
                If i < kFrameCount - 1 Then
                    Dim j As Integer = 0
                    Do While j < numPtsToInterpolateNow
                        Dim timeToInterpolate As Double
                        timeToInterpolate = currentKeyframe.TimeStamp + j * (timeDiff / (numPtsToInterpolateNow))

                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)

                        'get observer and target lat, long, alt after interpolation
                        globeCamera.GetObserverLatLonAlt(interLat, interLong, interAlt)
                        globeCamera.GetTargetLatLonAlt(interTarLat, interTarLong, interTarAlt)

                        'set observer and target lat, long, alt to original values before interpolation
                        globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt)
                        globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt)

                        Dim pObs As IPoint = New PointClass()
                        Dim obsZAware As IZAware = CType(pObs, IZAware)
                        obsZAware.ZAware = True
                        pObs.X = interLong
                        pObs.Y = interLat
                        pObs.Z = interAlt * 1000

                        Dim symbolSize As Double = 10000

                        'change the symbol size based on distance to ground
                        If pObs.Z >= 10000 Then
                            symbolSize = 10000 + pObs.Z / 10
                        Else
                            symbolSize = pObs.Z
                        End If

                        'add graphics - keyframes (j=0) are colored differently
                        If j = 0 Then
                            addPointGraphicElements(pObs, 2552550, symbolSize)
                        Else
                            addPointGraphicElements(pObs, 16732415, symbolSize)
                        End If

                        connectingLine.FromPoint = previousPt
                        connectingLine.ToPoint = pObs

                        'barring the first keyframe, create the line connecting the interpolated points
                        If i = 0 And j = 0 Then
                        Else
                            addLineGraphicElements(connectingLine, 150150150)
                        End If

                        'update the previous point
                        previousPt.PutCoords(pObs.X, pObs.Y)
                        previousPt.Z = pObs.Z

                        'add camera to target direction
                        If theCamForm.camToTargetDirectionCheckBox.Checked = True Then
                            cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt)
                        End If

                        globeDisplay.RefreshViewers()
                        j += 1
                    Loop
                End If

                'for last keyframe
                If i = kFrameCount - 1 Then
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                    currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)

                    globeCamera.GetObserverLatLonAlt(interLat, interLong, interAlt)
                    globeCamera.GetTargetLatLonAlt(interTarLat, interTarLong, interTarAlt)

                    globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt)
                    globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt)

                    Dim pObs As IPoint = New PointClass()
                    Dim obsZAware As IZAware = CType(pObs, IZAware)
                    obsZAware.ZAware = True
                    pObs.X = interLong
                    pObs.Y = interLat
                    pObs.Z = interAlt * 1000

                    Dim symbolSize As Double = 10000

                    If pObs.Z >= 10000 Then
                        symbolSize = 10000 + pObs.Z / 10
                    Else
                        symbolSize = pObs.Z
                    End If

                    connectingLine.FromPoint = previousPt
                    connectingLine.ToPoint = pObs

                    addPointGraphicElements(pObs, 2552550, symbolSize)
                    addLineGraphicElements(connectingLine, 150150150)

                    'add camera to target orientation
                    If theCamForm.camToTargetDirectionCheckBox.Checked = True Then
                        cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt)
                    End If

                    globeDisplay.RefreshViewers()
                End If
                i += 1
            Loop

            'enable buttons
            theCamForm.playButton.Enabled = True
            theCamForm.generatePathButton.Enabled = True
        End Sub

        'function for creating specified number of graphics between keyframe positions
        Public Sub generatePathBtwnKFrames()
            Dim numPtsBtwnKFrames As Integer = 0

            'this is the from point for the lines connecting the interpolated point graphics
            Dim previousPt As IPoint = New PointClass()
            Dim prevPtZAware As IZAware = CType(previousPt, IZAware)
            prevPtZAware.ZAware = True
            previousPt.PutCoords(0, 0)

            'this is the line connecting the interpolated camera positions
            Dim connectingLine As IPolyline = New PolylineClass()
            Dim lineZAware As IZAware = CType(connectingLine, IZAware)
            lineZAware.ZAware = True

            If theCamForm.ptsBtwnKframeTextBox.Text <> "" Then
                numPtsBtwnKFrames = Convert.ToInt32(theCamForm.ptsBtwnKframeTextBox.Text)
            Else
                MessageBox.Show("Please enter the number of points to be created")
                Return
            End If
            theCamForm.playButton.Enabled = False
            theCamForm.stopButton.Enabled = False
            theCamForm.generatePathButton.Enabled = False

            addGraphicLayer()

            Dim selectedTrack As String = theCamForm.animTracksListBox.SelectedItem.ToString()

            animationTracks.FindTrack(selectedTrack, animationTrack)

            Dim kFrames As IAGAnimationTrackKeyframes = CType(animationTrack, IAGAnimationTrackKeyframes)

            Dim kFrameCount As Integer = kFrames.KeyframeCount

            'loop over the keyframes in the selected camera track
            Dim i As Integer = 0
            Do While i < kFrameCount
                Dim currentKeyframe As IAGKeyframe = CType(kFrames.Keyframe(i), ESRI.ArcGIS.Animation.IAGKeyframe)
                Dim prevKeyframe As IAGKeyframe
                Dim nextKeyframe As IAGKeyframe
                Dim afterNextKeyframe As IAGKeyframe

                'if else statements to determine the keyframe arguments to the interpolate method
                'this is needed because the first and the last keyframes should be handled differently
                'than the middle keyframes
                If i > 0 Then
                    prevKeyframe = CType(kFrames.Keyframe(i - 1), ESRI.ArcGIS.Animation.IAGKeyframe)

                Else
                    prevKeyframe = CType(kFrames.Keyframe(i), ESRI.ArcGIS.Animation.IAGKeyframe)
                End If

                If i < kFrameCount - 1 Then
                    nextKeyframe = CType(kFrames.Keyframe(i + 1), ESRI.ArcGIS.Animation.IAGKeyframe)
                Else
                    nextKeyframe = CType(kFrames.Keyframe(i), ESRI.ArcGIS.Animation.IAGKeyframe)
                End If

                If i < kFrameCount - 2 Then
                    afterNextKeyframe = CType(kFrames.Keyframe(i + 2), ESRI.ArcGIS.Animation.IAGKeyframe)
                Else
                    'this should be equal to the nextKeyFrame for the last keyframe
                    afterNextKeyframe = nextKeyframe 'kFrames.Keyframe(i);
                End If

                Dim origCamLat, origCamLong, origCamAlt As Double
                Dim interLat, interLong, interAlt As Double
                Dim tarLat, tarLong, tarAlt As Double
                Dim interTarLat, interTarLong, interTarAlt As Double

                globeCamera.GetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt)
                globeCamera.GetTargetLatLonAlt(tarLat, tarLong, tarAlt)


                Dim pAnimContainer As IAGAnimationContainer = animationTracks.AnimationObjectContainer

                Dim objToInterpolate As Object = CObj(globeCamera)

                Dim timeDiff As Double = nextKeyframe.TimeStamp - currentKeyframe.TimeStamp

                'interpolate positions between keyframes and draw the graphics
                Dim j As Integer = 0
                Do While j < numPtsBtwnKFrames + 1
                    Dim timeToInterpolate As Double = currentKeyframe.TimeStamp + j * (timeDiff / (numPtsBtwnKFrames + 1))

                    'for 0 to n-1 keyframes
                    If i >= 0 And i < kFrameCount - 1 Then
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)
                        currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, timeToInterpolate, nextKeyframe, prevKeyframe, afterNextKeyframe)

                        globeCamera.GetObserverLatLonAlt(interLat, interLong, interAlt)
                        globeCamera.GetTargetLatLonAlt(interTarLat, interTarLong, interTarAlt)

                        globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt)
                        globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt)

                        Dim pObs As IPoint = New PointClass()
                        Dim obsZAware As IZAware = CType(pObs, IZAware)
                        obsZAware.ZAware = True
                        pObs.X = interLong
                        pObs.Y = interLat
                        pObs.Z = interAlt * 1000

                        Dim symbolSize As Double = 10000

                        If pObs.Z >= 10000 Then
                            symbolSize = 10000 + pObs.Z / 10
                        Else
                            symbolSize = pObs.Z
                        End If

                        If j = 0 Then
                            addPointGraphicElements(pObs, 2552550, symbolSize)
                        Else
                            addPointGraphicElements(pObs, 16732415, symbolSize)
                        End If

                        connectingLine.FromPoint = previousPt
                        connectingLine.ToPoint = pObs

                        If i = 0 And j = 0 Then
                        Else
                            addLineGraphicElements(connectingLine, 150150150)
                        End If

                        previousPt.PutCoords(pObs.X, pObs.Y)
                        previousPt.Z = pObs.Z

                        'add camera to target orientation
                        If theCamForm.camToTargetDirectionCheckBox.Checked = True Then
                            cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt)
                        End If

                        globeDisplay.RefreshViewers()

                        'for last keyframe
                    ElseIf i = kFrameCount - 1 Then
                        If j = 0 Then
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 4, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 5, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 6, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 1, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 2, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)
                            currentKeyframe.Interpolate(animationTrack, pAnimContainer, objToInterpolate, 3, 1, nextKeyframe, prevKeyframe, afterNextKeyframe)

                            globeCamera.GetObserverLatLonAlt(interLat, interLong, interAlt)
                            globeCamera.GetTargetLatLonAlt(interTarLat, interTarLong, interTarAlt)

                            globeCamera.SetObserverLatLonAlt(origCamLat, origCamLong, origCamAlt)
                            globeCamera.SetTargetLatLonAlt(tarLat, tarLong, tarAlt)

                            Dim pObs As IPoint = New PointClass()
                            Dim obsZAware As IZAware = CType(pObs, IZAware)
                            obsZAware.ZAware = True
                            pObs.X = interLong
                            pObs.Y = interLat
                            pObs.Z = interAlt * 1000

                            Dim symbolSize As Double = 10000

                            If pObs.Z >= 10000 Then
                                symbolSize = 10000 + pObs.Z / 10
                            Else
                                symbolSize = pObs.Z
                            End If

                            connectingLine.FromPoint = previousPt
                            connectingLine.ToPoint = pObs

                            addPointGraphicElements(pObs, 2552550, symbolSize)
                            addLineGraphicElements(connectingLine, 150150150)

                            'add camera to target orientation
                            If theCamForm.camToTargetDirectionCheckBox.Checked = True Then
                                cameraToTargetDirection(interLat, interLong, interAlt, interTarLat, interTarLong, interTarAlt)
                            End If

                            globeDisplay.RefreshViewers()
                        End If
                    End If
                    j += 1
                Loop
                i += 1
            Loop

            'enable buttons
            theCamForm.playButton.Enabled = True
            theCamForm.generatePathButton.Enabled = True
        End Sub

    'function for generating camera to target direction
    Public Sub cameraToTargetDirection(ByVal camLat As Double, ByVal camLong As Double, ByVal camAlt As Double, ByVal tarLat As Double, ByVal tarLong As Double, ByVal tarAlt As Double)
      Dim camPosition As IPoint = New PointClass()
      Dim targetPosition As IPoint = New PointClass()

      Dim pCamera As ICamera = CType(globeCamera, ICamera)

      Dim obsZAware As IZAware = CType(camPosition, IZAware)
      obsZAware.ZAware = True

      camPosition.PutCoords(camLong, camLat)
      camPosition.Z = camAlt * 1000

      Dim targetZAware As IZAware = CType(targetPosition, IZAware)
      targetZAware.ZAware = True

      targetPosition.PutCoords(tarLong, tarLat)
      targetPosition.Z = tarAlt

      Dim directionLine As IPolyline = New PolylineClass()
      Dim zAwareLine As IZAware = CType(directionLine, IZAware)
      zAwareLine.ZAware = True

      directionLine.FromPoint = camPosition
      directionLine.ToPoint = targetPosition


      addLineGraphicElements(directionLine, 255)

    End Sub

    'function for adding a graphics layer
    Public Sub addGraphicLayer()
      graphicsLayer = New GlobeGraphicsLayerClass()
      Dim pLayer As ILayer
      pLayer = CType(graphicsLayer, ILayer)
      pLayer.Name = "CameraPathGraphicsLayer"
      globe.AddLayerType(pLayer, esriGlobeLayerType.esriGlobeLayerTypeDraped, True)
    End Sub

    'function for adding point markers
    Public Sub addPointGraphicElements(ByVal inPoint As ESRI.ArcGIS.Geometry.IPoint, ByVal symbolColor As Integer, ByVal symbolSize As Double)
      Dim pElement As IElement = New MarkerElementClass()
      Dim symbol3d As ISimpleMarker3DSymbol = New SimpleMarker3DSymbolClass()

      Dim markerStyle As String = ""

      If Not theCamForm.symbolTypeListBox.SelectedItem Is Nothing Then
        markerStyle = theCamForm.symbolTypeListBox.SelectedItem.ToString()
      End If

      If markerStyle = "Cone" Then
      symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCone
      ElseIf markerStyle = "Sphere" Then
      symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSSphere
      ElseIf markerStyle = "Cylinder" Then
      symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCylinder
      ElseIf markerStyle = "Cube" Then
      symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCube
      ElseIf markerStyle = "Diamond" Then
      symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSDiamond
      ElseIf markerStyle = "Tetrahedron" Then
      symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSTetra
      Else
        symbol3d.Style = esriSimple3DMarkerStyle.esriS3DMSCone
      End If

      symbol3d.ResolutionQuality = 1
      Dim pColor As IColor = New RgbColorClass()
      pColor.RGB = symbolColor '16732415;

      Dim pMarkerSymbol As IMarkerSymbol
      pMarkerSymbol = CType(symbol3d, IMarkerSymbol)
      pMarkerSymbol.Color = pColor

      If symbolSize < 0 Then
      symbolSize = Math.Abs(symbolSize)
      End If
      If symbolSize = 0 Then
      symbolSize = 5000
      End If
      pMarkerSymbol.Size = symbolSize

      pElement.Geometry = inPoint
      Dim pMarkerElement As IMarkerElement
      pMarkerElement = CType(pElement, IMarkerElement)
      pMarkerElement.Symbol = pMarkerSymbol

      graphicsLayer.AddElement(pElement, 1)

    End Sub

    'function for adding line graphics elements
    Public Sub addLineGraphicElements(ByVal inLine As ESRI.ArcGIS.Geometry.IPolyline, ByVal symbolColor As Integer)
      Dim pElement As IElement = New LineElementClass() ' MarkerElementClass();
      Dim symbol3d As ISimpleLine3DSymbol = New SimpleLine3DSymbolClass()

      Dim markerStyle As String = ""

      If Not theCamForm.symbolTypeListBox.SelectedItem Is Nothing Then
        markerStyle = theCamForm.symbolTypeListBox.SelectedItem.ToString()
      End If

      If markerStyle = "Strip" Then
      symbol3d.Style = esriSimple3DLineStyle.esriS3DLSStrip
      ElseIf markerStyle = "Wall" Then
      symbol3d.Style = esriSimple3DLineStyle.esriS3DLSWall
      Else
        symbol3d.Style = esriSimple3DLineStyle.esriS3DLSTube
      End If

      symbol3d.ResolutionQuality = 1
      Dim pColor As IColor = New RgbColorClass()
      pColor.RGB = symbolColor

      Dim pLineSymbol As ILineSymbol
      pLineSymbol = CType(symbol3d, ILineSymbol)
      pLineSymbol.Color = pColor
      pLineSymbol.Width = 1

      pElement.Geometry = inLine
      Dim pLineElement As ILineElement
      pLineElement = CType(pElement, ILineElement)
      pLineElement.Symbol = pLineSymbol

      graphicsLayer.AddElement(pElement, 1)
    End Sub


    'event handlers
    Public Sub formPlayButtonClickEventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
      If Not theCamForm.animTracksListBox.SelectedItem Is Nothing Then
        enableSelectedTrack()
        'play the animation
        Me.playAnimation()
      Else
        MessageBox.Show("Please select a camera track", "Error")
      End If
    End Sub

    Public Sub formStopButtonClickEventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
      animPlayer.StopAnimation()
      theCamForm.stopButton.Enabled = False
      If theCamForm.generateCamPathCheckBox.Checked = True Then
      theCamForm.generatePathButton.Enabled = True
      End If
    End Sub

    Public Sub formGeneratePathButtonClickEventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
      If Not theCamForm.animTracksListBox.SelectedItem Is Nothing Then
        If theCamForm.ptsPerSecRadioButton.Checked = True Then
          If theCamForm.numPtsPerSecTextBox.Text = "" Then
            MessageBox.Show("Please enter number of points to be created per second", "Error")
            Return
          End If
          generatePathPerSecond()
        ElseIf theCamForm.ptsBtwnKframeRadioButton.Checked = True Then
          If theCamForm.ptsBtwnKframeTextBox.Text = "" Then
            MessageBox.Show("Please enter number of points to be created between keyframes", "Error")
            Return
          End If
          generatePathBtwnKFrames()
        End If
      Else
        MessageBox.Show("Please select a camera track")
      End If
    End Sub

    Public Sub formCheckbox1CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs)
      If theCamForm.generateCamPathCheckBox.Checked = True Then
      theCamForm.generatePathButton.Enabled = True
      Else
        theCamForm.generatePathButton.Enabled = False
      End If
    End Sub

    Private Sub theCamForm_Closing(ByVal sender As Object, ByVal e As CancelEventArgs)
      theCamForm.animTracksListBox.Items.Clear()
      toolIsInitialized = False
    End Sub

    Public Sub myAnimationEventHandler(ByVal animState As esriAnimationState)
      globeDispEvent = CType(globeDisplay, IGlobeDisplayEvents_Event)

      If animState = esriAnimationState.esriAnimationStopped Then
        theCamForm.playButton.Enabled = True
        theCamForm.generatePathButton.Enabled = True
        theCamForm.stopButton.Enabled = False
      End If
    End Sub

#End Region

  End Class

End Namespace