Maria globe client/Track interaction

From Maria GDK Wiki
Jump to navigation Jump to search

General

In this section, we will create and update a track, and observe the presentation in 2D and 3D mode.

, and For more details on track handling, see:

  • Tracks
  • Map interaction client:
Track interaction
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.

Track in map, 2D
Track in map, 2D

Track in map, 3D
Track in map, 3D