Maria globe client/Track interaction
In this section, we will create and update a track, and observe the presentation in 2D and 3D mode.
For more details on track handling, see Tracks, Map interaction client: Track interaction and Map interaction client: Track visualisation
Adding draw object layer and draw object view model
To be able to display tracks, we need to include a track layer in the globe client.
First, add a view model class, TrackViewModel, to handle the draw object interaction:
- Inheriting ViewModelBase
- Add a constructor taking a draw layer object as input
- Create and implement event handlers for:
- LayerInitialized event
- ServiceConnected event
public class TrackViewModel : ViewModelBase
{
private TrackLayer _trackLayer;
private MariaService _trackService;
public TrackViewModel(TrackLayer trackLayer)
{
_trackLayer = trackLayer;
_trackLayer.LayerInitialized += TrackLayer_LayerInitialized;
_trackLayer.ServiceConnected += TrackLayer_ServiceConnected;
}
private void TrackLayer_LayerInitialized()
{
_trackService = new MariaService("TrackService", "http://localhost:9008/tracks", BindingType.BasicHttp);
_trackLayer.TrackServices = new ObservableCollection<IMariaService> { _trackService };
}
private void TrackLayer_ServiceConnected(object sender, MariaServiceEventArgs args)
{
_trackLayer.ActiveTrackService = _trackLayer.TrackServices[0];
_trackLayer.ExtendedTrackLayer.TrackRefreshInterval = 1000;
_trackLayer.TrackLists = new ObservableCollection<string>(_trackLayer.GetTrackLists());
if (!_trackLayer.TrackLists.Contains("globeTest"))
_trackLayer.TrackLists.Add("globeTest");
_trackLayer.ActiveTrackList = "globeTest";
}
}
In the MainViewModel, add a track layer field, and in the constructor, add creation of the layer and TrackViewModel, and add the layer to the Layers list.
...
public TrackViewModel TrackViewModel { get; private set; }
public MainViewModel()
{
...
_trackLayer = new TrackLayer(GlobeMapManager);
TrackViewModel = new TrackViewModel(_trackLayer);
Layers.Add(_trackLayer);
}
...
Track utilities
Add the following GUI elements to your main window:
- Button for adding/updating the track
- Check box to enable/disable automatic track update (simulate movement)
The XAML could look something like this:
...
<GroupBox Header="Track">
<StackPanel>
<Button Margin="3"
Content="Track"
Command="{Binding TrackViewModel.TrackTestCmd}"/>
<CheckBox Margin="3"
Content="Auto update"
IsChecked="{Binding TrackViewModel.AutoUpdateActive}"/>
</StackPanel>
</GroupBox>
...
In TrackViewModel implement:
- command handler and command handler delegate in for the track update button
- auto update property with timer, initialised in during the LayerInitialized event handler.
...
private bool _autoUpdateActive;
Timer _autoUpdateTimer;
...
private void TrackLayer_LayerInitialized()
{
...
_autoUpdateTimer = new Timer(1000);
_autoUpdateTimer.Elapsed += OnAutoUpdateTimerTick;
}
...
public ICommand TrackTestCmd { get { return new DelegateCommand(CreateOrUpdateTrack, CheckAutoUpdate); } }
public void CreateOrUpdateTrack(object obj)
{
if (_trackLayer.ActiveTrackList == null)
return;
var currentTime = DateTime.UtcNow;
var strId = "Globe-Track";
var itemId = new ItemId(_trackLayer.ActiveTrackList, strId);
var list = _trackLayer.GetTrackData(strId);
var speed = RandomProvider.GetRandomDouble(100.0, 250.0);
var course = RandomProvider.GetRandomDouble(0, 360.0);
var pos = RandomProvider.GetRandomPosition(_trackLayer.GeoContext.Viewport.GeoRect, 0.9);
var altitude = RandomProvider.GetRandomDouble(500, 2000);
var roll = RandomProvider.GetRandomDouble(-45.0, 45.0);
var pitch = RandomProvider.GetRandomDouble(-30.0, 30.0);
ITrackData trackData;
if (!list.Any())
{
trackData = new TrackData(itemId, pos, course, speed) { ObservationTime = currentTime };
InitTrackData(ref trackData, strId);
}
else
{
trackData = list[0];
var trackAge = trackData.ObservationTime.HasValue ?
currentTime - trackData.ObservationTime.Value :
TimeSpan.MaxValue;
if (trackAge > new TimeSpan(0, 0, 5))
{
trackData = new TrackData(itemId, pos, course, speed) { ObservationTime = currentTime };
InitTrackData(ref trackData, strId);
}
else
{
trackData.ObservationTime = currentTime;
trackData.Speed = trackData.Speed.HasValue ?
RandomProvider.GetRandomDouble(trackData.Speed.Value * 0.8, trackData.Speed.Value * 1.2) :
speed;
trackData.Course = trackData.Course.HasValue ?
RandomProvider.GetRandomDouble(trackData.Course.Value * 0.9, trackData.Course.Value * 1.1) :
course;
trackData.Pos = trackData.Pos.HasValue ?
CalculateNewPos(trackData.Pos.Value, trackData.Speed.Value, trackData.Course.Value, trackAge) :
pos;
if (double.TryParse(trackData.Fields["altitude"], out altitude))
{
altitude = RandomProvider.GetRandomDouble(altitude * 0.8, altitude * 1.2);
}
if (double.TryParse(trackData.Fields["roll"], out roll))
{
roll = RandomProvider.GetRandomDouble(roll * 0.9, roll * 1.1);
}
if (double.TryParse(trackData.Fields["pitch"], out pitch))
{
pitch = RandomProvider.GetRandomDouble(pitch * 0.9, pitch * 1.1);
}
}
}
trackData.Fields["altitude"] = altitude.ToString();
trackData.Fields["roll"] = roll.ToString();
trackData.Fields["pitch"] = pitch.ToString();
trackData.Fields["heading"] = course.ToString();
_trackLayer.SetTrackData(trackData);
}
public bool CheckAutoUpdate(object obj)
{
return !AutoUpdateActive;
}
public bool AutoUpdateActive
{
get { return _autoUpdateActive; }
set
{
_autoUpdateActive = value;
if (_autoUpdateActive)
_autoUpdateTimer.Start();
else
_autoUpdateTimer.Stop();
}
}
private void OnAutoUpdateTimerTick(object sender, ElapsedEventArgs e)
{
CreateOrUpdateTrack(null);
}
private void InitTrackData(ref ITrackData td, string id)
{
td.Fields["name"] = id;
td.Fields["symbol.2525code"] = "SFAPCF----*****";
td.Fields["identity"] = "Friendly";
td.Fields["type"] = "F";
}
private GeoPos CalculateNewPos(GeoPos oldPos, double speed, double course, TimeSpan age)
{
var distance = speed * age.TotalSeconds;
var newPos = Earth.BearingRangeToPos(oldPos, new BearingRange(course, distance));
return newPos;
}
...
Track styling
Add a track style xml file to your project, and include it as a resource. You can find style xml to use here
Add the resource to the track layer in the LayerInitialized event handler in TrackViewModel.
...
private void TrackLayer_LayerInitialized()
{
_trackLayer.StyleXml = Properties.Resources.TrackStyle;
...
Running with track interaction
Running your application, observe the following:
- Pressing the track button, the track is created/moved around in the map area.
- The track button is disabled while auto-update is activated.