diff --git a/src/SampleApp.WinDesktop/MainWindow.xaml b/src/SampleApp.WinDesktop/MainWindow.xaml
index 2bb9bc0..8fdc921 100644
--- a/src/SampleApp.WinDesktop/MainWindow.xaml
+++ b/src/SampleApp.WinDesktop/MainWindow.xaml
@@ -44,72 +44,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
s);
@@ -46,7 +37,6 @@ namespace SampleApp.WinDesktop
//Use a log file for playing back logged data
var device = new NmeaParser.NmeaFileDevice("NmeaSampleData.txt");
-
StartDevice(device);
}
@@ -75,10 +65,9 @@ namespace SampleApp.WinDesktop
//Start new device
currentDevice = device;
currentDevice.MessageReceived += device_MessageReceived;
- mapView.LocationDisplay.DataSource = new NmeaLocationProvider(device);
- mapView.LocationDisplay.IsEnabled = true;
- mapView.LocationDisplay.InitialZoomScale = 5000;
- mapView.LocationDisplay.AutoPanMode = Esri.ArcGISRuntime.UI.LocationDisplayAutoPanMode.Navigation;
+ view2d.NmeaDevice = device;
+ view3d.NmeaDevice = device;
+
if (device is NmeaParser.NmeaFileDevice)
currentDeviceInfo.Text = string.Format("NmeaFileDevice( file={0} )", ((NmeaParser.NmeaFileDevice)device).FileName);
else if (device is NmeaParser.SerialPortDevice)
diff --git a/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj b/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj
index bb6195b..cc940bf 100644
--- a/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj
+++ b/src/SampleApp.WinDesktop/SampleApp.NetCore.csproj
@@ -4,8 +4,13 @@
WinExe
netcoreapp3.1
true
+ SampleApp.WinDesktop
+
+
+
+
@@ -14,8 +19,9 @@
NmeaSampleData.txt
PreserveNewest
-
-
+
+ PreserveNewest
+
\ No newline at end of file
diff --git a/src/SampleApp.WinDesktop/View2D.xaml b/src/SampleApp.WinDesktop/View2D.xaml
new file mode 100644
index 0000000..20ecbd3
--- /dev/null
+++ b/src/SampleApp.WinDesktop/View2D.xaml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SampleApp.WinDesktop/View2D.xaml.cs b/src/SampleApp.WinDesktop/View2D.xaml.cs
new file mode 100644
index 0000000..bf9408a
--- /dev/null
+++ b/src/SampleApp.WinDesktop/View2D.xaml.cs
@@ -0,0 +1,59 @@
+using Esri.ArcGISRuntime.Mapping;
+using NmeaParser;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace SampleApp.WinDesktop
+{
+ ///
+ /// Interaction logic for View2D.xaml
+ ///
+ public partial class View2D : UserControl
+ {
+ public View2D()
+ {
+ InitializeComponent();
+ if (mapView.Map == null)
+ {
+ mapView.Map = new Map(Basemap.CreateNavigationVector());
+ }
+
+ mapView.LocationDisplay.InitialZoomScale = 5000;
+ mapView.LocationDisplay.AutoPanMode = Esri.ArcGISRuntime.UI.LocationDisplayAutoPanMode.Navigation;
+ }
+
+ public NmeaDevice NmeaDevice
+ {
+ get { return (NmeaDevice)GetValue(NmeaDeviceProperty); }
+ set { SetValue(NmeaDeviceProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty NmeaDeviceProperty =
+ DependencyProperty.Register(nameof(NmeaDevice), typeof(NmeaDevice), typeof(View2D), new PropertyMetadata(null, OnNmeaDevicePropertyChanged));
+
+ private static void OnNmeaDevicePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ ((View2D)d).InitNmeaProvider(e.OldValue as NmeaDevice, e.NewValue as NmeaDevice);
+ }
+
+ private void InitNmeaProvider(NmeaDevice oldDevice, NmeaDevice newDevice)
+ {
+ mapView.LocationDisplay.IsEnabled = false;
+ if (newDevice != null)
+ {
+ mapView.LocationDisplay.DataSource = new NmeaLocationProvider(newDevice);
+ mapView.LocationDisplay.IsEnabled = true;
+ }
+ }
+ }
+}
diff --git a/src/SampleApp.WinDesktop/View3D.xaml b/src/SampleApp.WinDesktop/View3D.xaml
new file mode 100644
index 0000000..f6a9967
--- /dev/null
+++ b/src/SampleApp.WinDesktop/View3D.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/SampleApp.WinDesktop/View3D.xaml.cs b/src/SampleApp.WinDesktop/View3D.xaml.cs
new file mode 100644
index 0000000..42b91f3
--- /dev/null
+++ b/src/SampleApp.WinDesktop/View3D.xaml.cs
@@ -0,0 +1,120 @@
+using Esri.ArcGISRuntime.Geometry;
+using Esri.ArcGISRuntime.Mapping;
+using Esri.ArcGISRuntime.Symbology;
+using Esri.ArcGISRuntime.UI;
+using NmeaParser;
+using NmeaParser.Messages;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace SampleApp.WinDesktop
+{
+ ///
+ /// Interaction logic for View3D.xaml
+ ///
+ public partial class View3D : UserControl
+ {
+ public View3D()
+ {
+ InitializeComponent();
+ InitializeScene();
+ this.IsVisibleChanged += View3D_IsVisibleChanged;
+ }
+
+ private void View3D_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ if(IsVisible)
+ {
+ graphic3D.Geometry = null;
+ if (NmeaDevice != null)
+ NmeaDevice.MessageReceived += NmeaDevice_MessageReceived;
+ }
+ else
+ {
+ if (NmeaDevice != null)
+ NmeaDevice.MessageReceived -= NmeaDevice_MessageReceived;
+ }
+ }
+
+ private void NmeaDevice_MessageReceived(object sender, NmeaMessageReceivedEventArgs e)
+ {
+ if (e.Message is Rmc rmc)
+ UpdateLocation(rmc.Latitude, rmc.Longitude, rmc.Course);
+ }
+
+ private Graphic graphic3D;
+
+ private async void InitializeScene()
+ {
+ sceneView.Scene = new Scene(BasemapType.Imagery);
+ sceneView.Scene.BaseSurface.ElevationSources.Add(new ArcGISTiledElevationSource(new Uri("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer")));
+ sceneView.GraphicsOverlays.Add(new GraphicsOverlay() { Id = "Position", Renderer = new SimpleRenderer() });
+ sceneView.GraphicsOverlays["Position"].Renderer.SceneProperties.HeadingExpression = "[Heading]";
+
+ graphic3D = new Esri.ArcGISRuntime.UI.Graphic() { Symbol = SimpleMarkerSceneSymbol.CreateSphere(System.Drawing.Color.FromArgb(127, 255, 0, 0), 10) };
+ var symb = await ModelSceneSymbol.CreateAsync(new Uri("car.glb", UriKind.Relative));
+ symb.Width = 3; symb.Depth = 5; symb.Height = 2; symb.AnchorPosition = SceneSymbolAnchorPosition.Bottom;
+ graphic3D.Symbol = symb;
+ sceneView.GraphicsOverlays["Position"].Graphics.Add(graphic3D);
+
+ sceneView.CameraController = new OrbitGeoElementCameraController(sceneView.GraphicsOverlays["Position"].Graphics[0], 200);
+ }
+
+ private int updateId = 0;
+ private async void UpdateLocation(double latitude, double longitude, double newHeading)
+ {
+ // Handle 3D updates on 3D Scene
+ var cid = ++updateId;
+ var start = graphic3D.Geometry as MapPoint;
+ if (start == null)
+ {
+ graphic3D.Attributes["Heading"] = newHeading;
+ graphic3D.Geometry = new MapPoint(longitude, latitude, SpatialReferences.Wgs84);
+ }
+ else
+ {
+ var heading = (double)graphic3D.Attributes["Heading"];
+ if (double.IsNaN(heading))
+ graphic3D.Attributes["Heading"] = heading = newHeading;
+ var dx = longitude - start.X;
+ var dy = latitude - start.Y;
+ var dh = newHeading - heading;
+ if (dh < -180) dh += 360;
+ else if (dh > 180) dh -= 360;
+ // Interpolate position update over 16 frames
+ for (int i = 0; i < 60; i++)
+ {
+ if (updateId != cid) break;
+ graphic3D.Geometry = new MapPoint(start.X + dx * i / 60d, start.Y + dy * i / 60d, start.SpatialReference);
+ var h = heading + dh * i / 60d;
+ if (h > 360) h -= 360;
+ else if (h < 0) h += 360;
+ graphic3D.Attributes["Heading"] = h;
+ await Task.Delay(16).ConfigureAwait(false);
+ }
+ }
+ }
+
+ public NmeaDevice NmeaDevice
+ {
+ get { return (NmeaDevice)GetValue(NmeaDeviceProperty); }
+ set { SetValue(NmeaDeviceProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty NmeaDeviceProperty =
+ DependencyProperty.Register(nameof(NmeaDevice), typeof(NmeaDevice), typeof(View3D), new PropertyMetadata(null));
+
+ }
+}
diff --git a/src/SampleApp.WinDesktop/car.glb b/src/SampleApp.WinDesktop/car.glb
new file mode 100644
index 0000000..7f2c8dc
Binary files /dev/null and b/src/SampleApp.WinDesktop/car.glb differ
diff --git a/src/SampleApp.WinDesktop/simplecar.glb b/src/SampleApp.WinDesktop/simplecar.glb
new file mode 100644
index 0000000..68873f0
Binary files /dev/null and b/src/SampleApp.WinDesktop/simplecar.glb differ