Dynamic display — tracking dynamic object
TrackObject.cs
// Copyright 2006 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the use restrictions.
//
using System;
using System.Xml;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Timers;
using System.Windows.Forms;
using ESRI.ArcGIS.Controls;
using System.Collections.Generic;
using Microsoft.Win32;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.SystemUI;
namespace DynamicObjectTracking
{
/// <summary>
/// A helper method used to delegate calls to the main thread
/// </summary>
public sealed class InvokeHelper : Control
{
//delegate used to pass the invoked method to the main thread
public delegate void MessageHandler(NavigationData navigationData);
//class members
private IActiveView m_activeView;
private IPoint m_point = null;
/// <summary>
/// class constructor
/// </summary>
/// <param name="activeView"></param>
public InvokeHelper(IActiveView activeView)
{
//make sure tha the control got created and that it has a valid handle
this.CreateHandle();
this.CreateControl();
//get the active view
m_activeView = activeView;
}
/// <summary>
/// delegate the required method onto the main thread
/// </summary>
/// <param name="navigationData"></param>
public void InvokeMethod(NavigationData navigationData)
{
try
{
// Invoke the HandleMessage through its delegate
if (!this.IsDisposed && this.IsHandleCreated)
Invoke(new MessageHandler(CenterMap), new object[] { navigationData });
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
/// <summary>
/// the method that gets executed by the delegate
/// </summary>
/// <param name="navigationData"></param>
public void CenterMap(NavigationData navigationData)
{
try
{
//get the current map visible extent
IEnvelope envelope = m_activeView.ScreenDisplay.DisplayTransformation.VisibleBounds;
if (null == m_point)
{
m_point = new PointClass();
}
//set the new map center coordinate
m_point.PutCoords(navigationData.X, navigationData.Y);
//center the map around the new coordinate
envelope.CenterAt(m_point);
m_activeView.ScreenDisplay.DisplayTransformation.VisibleBounds = envelope;
//rotate the map to the new rotation angle
m_activeView.ScreenDisplay.DisplayTransformation.Rotation = navigationData.Azimuth;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
/// <summary>
/// control's initialization
/// </summary>
private void InitializeComponent()
{
}
}
/// <summary>
/// A user defined data structure used to pass information to the invoke method
/// </summary>
public struct NavigationData
{
public double X;
public double Y;
public double Azimuth;
/// <summary>
/// struct constructor
/// </summary>
/// <param name="x">map x coordinate</param>
/// <param name="y">map x coordinate</param>
/// <param name="azimuth">the new map azimuth</param>
public NavigationData(double x, double y, double azimuth)
{
X = x;
Y = y;
Azimuth = azimuth;
}
}
/// <summary>
/// This command triggers the tracking functionality using Dynamic Display
/// </summary>
[Guid("803D4188-AB2F-49f9-9340-42C809887063")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("DynamicObjectTracking.TrackObject")]
public sealed class TrackObject : BaseCommand
{
#region COM Registration Function(s)
[ComRegisterFunction()]
[ComVisible(false)]
static void RegisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryRegistration(registerType);
//
// TODO: Add any COM registration code here
//
}
[ComUnregisterFunction()]
[ComVisible(false)]
static void UnregisterFunction(Type registerType)
{
// Required for ArcGIS Component Category Registrar support
ArcGISCategoryUnregistration(registerType);
//
// TODO: Add any COM unregistration code here
//
}
#region ArcGIS Component Category Registrar generated code
/// <summary>
/// Required method for ArcGIS Component Category registration -
/// Do not modify the contents of this method with the code editor.
/// </summary>
private static void ArcGISCategoryRegistration(Type registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID);
ControlsCommands.Register(regKey);
MxCommands.Register(regKey);
}
/// <summary>
/// Required method for ArcGIS Component Category unregistration -
/// Do not modify the contents of this method with the code editor.
/// </summary>
private static void ArcGISCategoryUnregistration(Type registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID);
ControlsCommands.Unregister(regKey);
MxCommands.Unregister(regKey);
}
#endregion
#endregion
//class members
private IHookHelper m_hookHelper = null;
private string m_navigationDataFileName = string.Empty;
private IPoint m_point = null;
private List<WKSPoint> m_points = null;
private System.Timers.Timer m_timer = null;
private InvokeHelper m_invokeHelper = null;
private ObjectLocationClass m_objectLocation = null;
private static int m_pointIndex = 0;
private bool m_bIsRunning = false;
private bool m_bOnce = true;
/// <summary>
/// class constructor
/// </summary>
public TrackObject()
{
base.m_category = ".NET Samples";
base.m_caption = "Track Dynamic Object";
base.m_message = "Tracking a dynamic object";
base.m_toolTip = "Tracking a dynamic object";
base.m_name = "DotNetSamples.TrackDynamicObject";
try
{
string bitmapResourceName = GetType().Name + ".bmp";
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
}
}
#region Overriden Class Methods
/// <summary>
/// Occurs when this command is created
/// </summary>
/// <param name="hook">Instance of the application</param>
public override void OnCreate(object hook)
{
if (hook == null)
return;
if (m_hookHelper == null)
m_hookHelper = new HookHelperClass();
m_hookHelper.Hook = hook;
//get the ArcGIS path from the registry
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ESRI\ArcGIS");
string path = Convert.ToString(key.GetValue("InstallDir"));
//set the path to the featureclass used by the GPS simulator
m_navigationDataFileName = System.IO.Path.Combine(path, @"DeveloperKit\SamplesNET\data\USAMajorHighways\NavigationData.xml");
m_point = new PointClass();
m_points = new List<WKSPoint>();
//instantiate the timer
m_timer = new System.Timers.Timer(60);
m_timer.Enabled = false;
//set the timer's elapsed event handler
m_timer.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
}
/// <summary>
/// Occurs when this command is clicked
/// </summary>
public override void OnClick()
{
//create the Invoke helper class
if (null == m_invokeHelper)
m_invokeHelper = new InvokeHelper(m_hookHelper.ActiveView);
//make sure to switch into dynamic mode
IDynamicMap dynamicMap = (IDynamicMap)m_hookHelper.FocusMap;
if (!dynamicMap.DynamicMapEnabled)
dynamicMap.DynamicMapEnabled = true;
//do some initializations...
if (m_bOnce)
{
//generate the navigation data
GenerateNavigationData();
//initialize the dynamic layer which will be used to draw the tracked object
m_objectLocation = new ObjectLocationClass();
//add the dynamic layer to the map
m_hookHelper.FocusMap.AddLayer(m_objectLocation);
m_bOnce = false;
}
//Start the tracking timer
if(!m_bIsRunning)
m_timer.Enabled = true;
else
m_timer.Enabled = false;
//set the running flag
m_bIsRunning = !m_bIsRunning;
}
/// <summary>
/// set the state of the button of the command
/// </summary>
public override bool Checked
{
get
{
return m_bIsRunning;
}
}
#endregion
/// <summary>
/// Timer elapsed event handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
//make sure that the current tracking point index does not exceed the list index
if (m_pointIndex == (m_points.Count - 1))
{
m_timer.Enabled = false;
return;
}
//get the current and the next track location
WKSPoint currentPoint = m_points[m_pointIndex];
WKSPoint nextPoint = m_points[m_pointIndex + 1];
//calculate the azimuth to the next location
double azimuth = (180.0 / Math.PI) * Math.Atan2(nextPoint.X - currentPoint.X, nextPoint.Y - currentPoint.Y);
//create the navigation data structure
NavigationData navigationData = new NavigationData(currentPoint.X, currentPoint.Y, azimuth);
//update the map extent and rotation
m_invokeHelper.InvokeMethod(navigationData);
//add the navigation data to the loction layer in order to draw it
m_objectLocation.AddNavigationData(navigationData);
//increment the tracking point index
m_pointIndex++;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
private void GenerateNavigationData()
{
try
{
if (!System.IO.File.Exists(m_navigationDataFileName))
{
throw new Exception("File " + m_navigationDataFileName + " cannot be found!");
}
XmlTextReader reader = new XmlTextReader(m_navigationDataFileName);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
reader.Close();
double X;
double Y;
//get the navigation items
XmlNodeList nodes = doc.DocumentElement.SelectNodes("./navigationItem");
foreach (XmlNode node in nodes)
{
X = Convert.ToDouble(node.Attributes[0].Value);
Y = Convert.ToDouble(node.Attributes[1].Value);
WKSPoint p = new WKSPoint();
p.X = X;
p.Y = Y;
m_points.Add(p);
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
}
}