Maria globe client
This page describes how to create a Maria GDK map client utilising MariaGlobeMapControl with 2D and 3D visualisation of map, tracks and draw objects.
General
This page is under construction!
- Note
-
- You will need to include the TPG.Maria.MariaGlobeMapControl NuGet package (Currently available Teleplan Globe internal only)
- Sample code is found in the MariaGlobeClient project, in the Sample Projects solution.
- Note that the sample code is specifying the service connections in code, and not by app.config.
- For general troubleshooting, see Development troubleshooting
Auto follow
In this section, we will utilise the globe control auto follow functionality.
- 2D
-
- valid for tracks and all draw object types
- the specified object will always be displayed with its center point in the center of the screen.
- if the item position is changed, the map area will be adjusted accordingly.
- 3D
-
- valid for tracks and point objects only
Auto follow control and display
Add the following GUI elements to your main window:
- Check box to enable/disable auto follow
- Text box for display of currently followed item
The XAML could look something like this:
...
<GroupBox Header="Auto follow">
<StackPanel>
<CheckBox Margin="3"
Content="Follow selected"
IsChecked="{Binding IsAutoFollowActive}" />
<Label Content="Currently followed:" FontWeight="DemiBold" />
<TextBox Margin="3"
Text="{Binding AutoFollowItemName, Mode=OneWay}"
IsReadOnly="True"/>
</StackPanel>
</GroupBox>
...
In MainViewModel implement:
- Auto follow property,
- auto update property with timer, initialised in during the LayerInitialized event handler.
...
public bool IsAutoFollowActive
{
get
{
return GlobeMapViewModel.AutoFollow.TargetItem != null;
}
set
{
if (!(value && GlobeMapViewModel.AutoFollow.FollowSelectedItem()))
GlobeMapViewModel.AutoFollow.TargetItem = null;
NotifyPropertyChanged(() => IsAutoFollowActive);
NotifyPropertyChanged(() => AutoFollowItemName);
}
}
public string AutoFollowItemName
{
get
{
if (GlobeMapViewModel?.AutoFollow?.TargetItem != null)
{
return GlobeMapViewModel.AutoFollow.TargetItem.ToString();
}
return "Inactive";
}
}
...
Running with auto follow
Activating/deactivating auto follow functionality, observe the following:
- in 3D mode, tracks and point objects only can be selected.
- the map will re-position to the activated item if the map is panned.
- the map will re-position to the activated item if the item is moved.
- the activated item will stay activated also when deselected in the map and when another item is selected.
- To activate another item - deactivate, then activate the new item.
No auto follow, 2D | |
Auto follow volume object, 2D |
Auto follow line object, 2D |
Auto follow point object, 2D |
Auto follow track, 2D |
Auto follow point object, 3D |
Auto follow track, 3D |
Advanced map settings
Map rotation
As default, 2D maps are displayed with north up, but you may rotate the map by modifying the map layer rotation parameter - GeoContext.RotateValue.
Add the following components:
- Text box to display the current rotation value
- Two buttons, for right (clockwise) add left (counter clockwise).
Add the following to your Main Window XAML:
. . .
<Label Grid.Row="4" Grid.Column="0"
Content="Rotation" FontWeight="DemiBold"/>
<TextBox Grid.Row="4" Grid.Column="1" Margin="3"
Text="{Binding MapViewModel.Rotation}" TextAlignment="Right" />
<StackPanel Grid.Row="5" Grid.Column="1" Orientation="Horizontal"
VerticalAlignment="Center" HorizontalAlignment="Center">
<RepeatButton Margin="3" Width="50"
Content="Left"
Command="{Binding MapViewModel.RotateLeftCmnd}"/>
<RepeatButton Margin="3" Width="50"
Content="Right"
Command="{Binding MapViewModel.RotateRightCmnd}"/>
</StackPanel>
. . .
And implement corresponding properties and command handlers in MapViewModel:
. . .
public ICommand RotateLeftCmnd { get { return new DelegateCommand(OnRotateLeft); } }
public ICommand RotateRightCmnd { get { return new DelegateCommand(OnRotateRight); } }
private void OnRotateLeft(object obj)
{
Rotation += 1;
}
private void OnRotateRight(object obj)
{
Rotation -= 1;
}
public int Rotation
{
get { return _mapLayer.GeoContext != null ? (int)_mapLayer.GeoContext.RotateValue : 0; }
set
{
_mapLayer.GeoContext.RotateValue = value;
NotifyPropertyChanged(() => Rotation);
}
}
. . .
Pressing the buttons, the map is rotated, and the rotation display is updated accordingly.
3D map settings
3D Properties
The Globe Client 3D view is the view from a camera towards a target, specified by the following parameters:
- Note
-
- 3D rotations are not commutative.
- Performing the same rotations in different order will give different results.
Implementation
To visualise how these parameters are connected, add the following elements to your main window:
. . .
<GroupBox Header="3D Settings"
IsEnabled="{Binding MapViewModel.Is3DMode}" >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4"
Content="Camera" FontWeight="DemiBold" />
<Label Grid.Row="1" Grid.Column="0"
Content="Yaw" />
<TextBox Grid.Row="1" Grid.Column="1" Margin="3" Width="60"
Text="{Binding MapViewModel.CameraYaw, StringFormat=N2}" TextAlignment="Right"
IsReadOnly="True"/>
<RepeatButton Grid.Row="1" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreaseYawCmnd}"/>
<RepeatButton Grid.Row="1" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreaseYawCmnd}"/>
<Label Grid.Row="2" Grid.Column="0"
Content="Roll" />
<TextBox Grid.Row="2" Grid.Column="1" Margin="3" Width="60"
Text="{Binding MapViewModel.CameraRoll, StringFormat=N2}" TextAlignment="Right"
IsReadOnly="True"/>
<RepeatButton Grid.Row="2" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreaseRollCmnd}"/>
<RepeatButton Grid.Row="2" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreaseRollCmnd}"/>
<Label Grid.Row="3" Grid.Column="0"
Content="Pitch" />
<TextBox Grid.Row="3" Grid.Column="1" Margin="3" Width="60"
Text="{Binding MapViewModel.CameraPitch, StringFormat=N2}" TextAlignment="Right"
IsReadOnly="True"/>
<RepeatButton Grid.Row="3" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreasePitchCmnd}"/>
<RepeatButton Grid.Row="3" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreasePitchCmnd}"/>
<Label Grid.Row="4" Grid.Column="0"
Content="Target" FontWeight="DemiBold" />
<CheckBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="3" VerticalAlignment="Center" Margin="3"
Content="Follow ground"
IsChecked="{Binding MapViewModel.FollowGround}"/>
<Label Grid.Row="5" Grid.Column="0"
Content="Altitude" />
<TextBox Grid.Row="5" Grid.Column="1" Margin="3" Width="60"
Text="{Binding MapViewModel.TargetAltitude, StringFormat=N0}" TextAlignment="Right"
IsReadOnly="True"/>
<RepeatButton Grid.Row="5" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreaseTargetAltitudeCmnd}"/>
<RepeatButton Grid.Row="5" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreaseTargetAltitudeCmnd}"/>
<Label Grid.Row="6" Grid.Column="0"
Content="Distance" />
<TextBox Grid.Row="6" Grid.Column="1" Margin="3" Width="60"
Text="{Binding MapViewModel.TargetDistance, StringFormat=N0}" TextAlignment="Right"
IsReadOnly="True"/>
<RepeatButton Grid.Row="6" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreaseTargetDistanceCmnd}"/>
<RepeatButton Grid.Row="6" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreaseTargetDistanceCmnd}"/>
<Label Grid.Row="7" Grid.Column="0"
Content="Position" />
<TextBox Grid.Row="7" Grid.Column="1" Grid.ColumnSpan="3" Margin="3"
Text="{Binding MapViewModel.TargetPosText, Mode=OneWay}" TextAlignment="Right"
IsReadOnly="True"/>
<Label Grid.Row="8" Grid.Column="1"
Content="Latitude"/>
<RepeatButton Grid.Row="8" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreaseTargetPosLatCmnd}"/>
<RepeatButton Grid.Row="8" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreaseTargetPosLatCmnd}"/>
<Label Grid.Row="9" Grid.Column="1"
Content="Longitude"/>
<RepeatButton Grid.Row="9" Grid.Column="2" Width="12" Margin="3" HorizontalAlignment="Center"
Content="+"
Command="{Binding MapViewModel.IncreaseTargetPosLonCmnd}"/>
<RepeatButton Grid.Row="9" Grid.Column="3" Width="12" Margin="3" HorizontalAlignment="Center"
Content="-"
Command="{Binding MapViewModel.DecreaseTargetPosLonCmnd}"/>
</Grid>
</GroupBox>
. . .
And add necessary command handlers and properties to MapViewModel
. . .
public ICommand IncreaseYawCmnd { get { return new DelegateCommand(OnIncreaseCameraYaw); } }
public ICommand DecreaseYawCmnd { get { return new DelegateCommand(OnDecreaseCameraYaw); } }
public ICommand IncreaseRollCmnd { get { return new DelegateCommand(OnIncreaseCameraRoll); } }
public ICommand DecreaseRollCmnd { get { return new DelegateCommand(OnDecreaseCameraRoll); } }
public ICommand IncreasePitchCmnd { get { return new DelegateCommand(OnIncreaseCameraPitch); } }
public ICommand DecreasePitchCmnd { get { return new DelegateCommand(OnDecreaseCameraPitch); } }
public ICommand IncreaseTargetDistanceCmnd { get { return new DelegateCommand(OnIncreaseTargetDistance); } }
public ICommand DecreaseTargetDistanceCmnd { get { return new DelegateCommand(OnDecreaseTargetDistance); } }
public ICommand IncreaseTargetAltitudeCmnd { get { return new DelegateCommand(OnIncreaseTargetAlttitude, CanModTargetAltitude); } }
public ICommand DecreaseTargetAltitudeCmnd { get { return new DelegateCommand(OnDecreaseTargetAltitide, CanModTargetAltitude); } }
public ICommand IncreaseTargetPosLatCmnd { get { return new DelegateCommand(OnIncreaseTargetPosLat, CanModTargetPosition); } }
public ICommand DecreaseTargetPosLatCmnd { get { return new DelegateCommand(OnDecreaseTargetPosLat, CanModTargetPosition); } }
public ICommand IncreaseTargetPosLonCmnd { get { return new DelegateCommand(OnIncreaseTargetPosLon, CanModTargetPosition); } }
public ICommand DecreaseTargetPosLonCmnd { get { return new DelegateCommand(OnDecreaseTargetPosLon, CanModTargetPosition); } }
public bool Autofollow
{
get { return _autoFollow; }
set
{
_autoFollow = value;
RefreshTargetAndCameraValues();
}
}
private void OnIncreaseCameraYaw(object obj) { CameraYaw += 1; }
private void OnDecreaseCameraYaw(object obj) { CameraYaw -= 1; }
private void OnIncreaseCameraRoll(object obj) { CameraRoll += 1; }
private void OnDecreaseCameraRoll(object obj) { CameraRoll -= 1; }
private void OnIncreaseCameraPitch(object obj) { CameraPitch += 1; }
private void OnDecreaseCameraPitch(object obj) { CameraPitch -= 1; }
private void OnIncreaseTargetAlttitude(object obj) { TargetAltitude += 10; }
private void OnDecreaseTargetAltitide(object obj) { TargetAltitude -= 10; }
private void OnIncreaseTargetPosLat(object obj) { TargetPos = new GeoPos(TargetPos.Lat + (1.0 / (60 * 60)), TargetPos.Lon ); }
private void OnDecreaseTargetPosLat(object obj) { TargetPos = new GeoPos(TargetPos.Lat - (1.0 / (60 * 60)), TargetPos.Lon ); }
private void OnIncreaseTargetPosLon(object obj) { TargetPos = new GeoPos(TargetPos.Lat, TargetPos.Lon + (1.0 / (60 * 60))); }
private void OnDecreaseTargetPosLon(object obj) { TargetPos = new GeoPos(TargetPos.Lat, TargetPos.Lon - (1.0 / (60 * 60))); }
private bool CanModTargetAltitude(object obj) { return !FollowGround && !Autofollow; }
private bool CanModTargetPosition(object obj) { return !Autofollow; }
private void OnIncreaseTargetDistance(object obj) { TargetDistance += 10; }
private void OnDecreaseTargetDistance(object obj) { TargetDistance -= 10; }
public double CameraYaw
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.Yaw;
return 0;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.Yaw = value;
}
NotifyPropertyChanged(() => CameraYaw);
}
}
public double CameraRoll
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.Roll;
return 0;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.Roll = value;
}
NotifyPropertyChanged(() => CameraRoll);
}
}
public double CameraPitch
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.Pitch;
return 0;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.Pitch = value;
}
NotifyPropertyChanged(() => CameraPitch);
}
}
public string TargetPosText { get { return TargetPos.ToString(); } }
public GeoPos TargetPos
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.TargetPos;
return GeoPos.InvalidPos;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.TargetPos = value;
}
RefreshTargetAndCameraValues();
}
}
public double TargetAltitude
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.TargetAltitude;
return 0;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.TargetAltitude = value;
}
NotifyPropertyChanged(() => TargetAltitude);
}
}
public bool FollowGround
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.FollowGround;
return true;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.FollowGround = value;
}
NotifyPropertyChanged(() => FollowGround);
}
}
public double TargetDistance
{
get
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
return GlobeMapViewModel.Globe3DViewModel.CameraControl.TargetDistance;
return 0;
}
set
{
if (GlobeMapViewModel?.Globe3DViewModel?.CameraControl != null)
{
GlobeMapViewModel.Globe3DViewModel.CameraControl.TargetDistance = value;
}
NotifyPropertyChanged(() => TargetDistance);
}
}
. . .
private void RefreshTargetAndCameraValues()
{
NotifyPropertyChanged(() => FollowGround);
NotifyPropertyChanged(() => Autofollow);
NotifyPropertyChanged(() => CameraPitch);
NotifyPropertyChanged(() => CameraRoll);
NotifyPropertyChanged(() => CameraYaw);
NotifyPropertyChanged(() => TargetAltitude);
NotifyPropertyChanged(() => TargetPos);
NotifyPropertyChanged(() => TargetPosText);
NotifyPropertyChanged(() => TargetDistance);
}
. . .
... and update MapViewModel.Autofollow when auto follow has changed in MainViewModel!
. . .
public bool IsAutoFollowActive
{
. . .
set
{
if (!(value && GlobeMapViewModel.AutoFollow.FollowSelectedItem()))
GlobeMapViewModel.AutoFollow.TargetItem = null;
MapViewModel.Autofollow = IsAutoFollowActive;
NotifyPropertyChanged(() => IsAutoFollowActive);
NotifyPropertyChanged(() => AutoFollowItemName);
}
}
. . .
Running with display of 3D settings
Running the Globe client in 3D mode, altering the 3D parameters will give results like this: