SOE Elevation Profile Viewer
This sample demonstrates how to use a custom Server Object Extension (SOE) hosted by ArcGIS Server. More information on SOEs can be found here.
The SOE is accessible via the ArcGIS for Server REST API. A web request is programmatically constructed by populating argument\value pairs to match parameters defined by the SOE's REST schema (discoverable via the ArcGIS for Server REST Services Directory). The response from the SOE contains string data in JSON (JavaScript Object Notation) format.
Download Sample Application<UserControl x:Class="ArcGISWPFSDK.SOEElevationProfileViewer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:esri="http://schemas.esri.com/arcgis/client/2009" xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"> <Grid> <DockPanel LastChildFill="True"> <Grid DockPanel.Dock="Bottom" Name="bottomGrid" Visibility="Collapsed"> <Grid Height="200"> <chartingToolkit:Chart Name="profileChart" Title="Elevation Profile" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <chartingToolkit:Chart.LegendStyle> <Style TargetType="Control"> <Setter Property="Width" Value="0"/> <Setter Property="Height" Value="0"/> </Style> </chartingToolkit:Chart.LegendStyle> <chartingToolkit:AreaSeries DependentValuePath="Value" IndependentValuePath="Key" ItemsSource="{Binding Path=ValueList}" IsSelectionEnabled="True" Height="100" Background="{x:Null}" Foreground="Blue"> <chartingToolkit:AreaSeries.DependentRangeAxis> <chartingToolkit:LinearAxis Minimum="{Binding Path=Info[0]}" Maximum="{Binding Path=Info[1]}" Orientation="Y" Interval="{Binding Path=Info[2]}" ShowGridLines="True"></chartingToolkit:LinearAxis> </chartingToolkit:AreaSeries.DependentRangeAxis> <chartingToolkit:AreaSeries.PathStyle> <Style TargetType="Path"> <Setter Property="Stroke" Value="DarkBlue"/> <Setter Property="StrokeThickness" Value="2.5"/> <Setter Property="Opacity" Value="0.75"/> </Style> </chartingToolkit:AreaSeries.PathStyle> <chartingToolkit:AreaSeries.DataPointStyle> <Style TargetType="{x:Type chartingToolkit:AreaDataPoint}"> <Setter Property="Width" Value="7"/> <Setter Property="Height" Value="7"/> <Setter Property="Background" Value="DodgerBlue"/> <Setter Property="DependentValueStringFormat" Value="Elevation = {0:N2} meters"/> </Style> </chartingToolkit:AreaSeries.DataPointStyle> </chartingToolkit:AreaSeries> </chartingToolkit:Chart> <Grid.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="White" Offset="0" /> <GradientStop Color="#FFADABAB" Offset="1" /> <GradientStop Color="#FFF0F0F0" Offset="0.206" /> </LinearGradientBrush> </Grid.Background> </Grid> </Grid> <Grid x:Name="LayoutRoot"> <Grid.Resources> <esri:SimpleMarkerSymbol x:Key="RedCircleSymbol" Color="Red" Style="Circle" Size="11" /> <esri:SimpleLineSymbol x:Key="BlueLineSymbol" Color="Blue" Width="4" /> <esri:SimpleFillSymbol x:Key="GreenFillSymbol" Fill="Transparent" BorderBrush="Green" BorderThickness="4" /> </Grid.Resources> <esri:Map x:Name="MyMap" UseAcceleratedDisplay="True" Extent="-15000000,2000000,-7000000,8000000"> <esri:ArcGISTiledMapServiceLayer ID="National Geographic" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer"/> <esri:GraphicsLayer ID="inputsGraphicsLayer"/> </esri:Map> <Border BorderBrush="Black" BorderThickness="1" Height="135" Width="175" HorizontalAlignment="Left" VerticalAlignment="Top" Background="White" Margin="10"> <Border.Effect> <DropShadowEffect ShadowDepth="1" /> </Border.Effect> <StackPanel> <TextBlock Text="Elevation Profile:" FontWeight="Bold" TextWrapping="Wrap" Margin="5,5,5,0"/> <TextBlock Text="Click Get Elevation Profile then draw a line on the map to retrieve the elevation profile." TextWrapping="Wrap" Margin="5,5,5,0"/> <Button x:Name="GetProfileButton" Click="GetProfileButton_Click" Content="Get Elevation Profile" ToolTip="Get Elevation Profile" Height="auto" HorizontalAlignment="Center" VerticalAlignment="Top" Width="auto" Margin="5"> </Button> <Button x:Name="ClearButton" Click="ClearButton_Click" Content="Clear Results" ToolTip="Clear" Height="auto" HorizontalAlignment="Center" VerticalAlignment="Top" Width="auto" Margin="5,0,5,5"> </Button> </StackPanel> </Border> </Grid> </DockPanel> </Grid> </UserControl>
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Web.Script.Serialization; using ESRI.ArcGIS.Client.Geometry; using System.Collections; using System.Collections.ObjectModel; using System.Net; using System.IO; using ESRI.ArcGIS.Client; using ESRI.ArcGIS.Client.Symbols; namespace ArcGISWPFSDK { public partial class SOEElevationProfileViewer : UserControl { private static string ELEVATION_MAPSERVICE_URL = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Elevation/WorldElevations/MapServer/"; private static string ELEVATION_SOE_NAME = "ElevationsSOE_NET"; private static int ELEVATION_RESOURCE_INDEX = 0; private Draw _drawObject; private Symbol currentSymbol; private ElevationsSOEUtils soeUtils; private ElevationValues elevationValues; public SOEElevationProfileViewer() { InitializeComponent(); soeUtils = new ElevationsSOEUtils(ELEVATION_MAPSERVICE_URL, ELEVATION_SOE_NAME, ELEVATION_RESOURCE_INDEX); soeUtils.GetElevationsEvent += new EventHandler(soeUtils_GetElevationsEvent); _drawObject = new Draw(MyMap) { FillSymbol = LayoutRoot.Resources["GreenFillSymbol"] as FillSymbol, LineSymbol = LayoutRoot.Resources["BlueLineSymbol"] as LineSymbol }; _drawObject.DrawBegin += MyDrawObject_OnDrawBegin; _drawObject.DrawComplete += MyDrawObject_OnDrawComplete; elevationValues = new ElevationValues(); profileChart.DataContext = elevationValues; } private void GetProfileButton_Click(object sender, RoutedEventArgs e) { _drawObject.IsEnabled = false; currentSymbol = LayoutRoot.Resources["BlueLineSymbol"] as Symbol; _drawObject.DrawMode = DrawMode.Polyline; _drawObject.IsEnabled = true; } private void MyDrawObject_OnDrawBegin(object sender, EventArgs args) { GraphicsLayer graphicsLayer = MyMap.Layers["inputsGraphicsLayer"] as GraphicsLayer; graphicsLayer.Graphics.Clear(); } private void MyDrawObject_OnDrawComplete(object sender, DrawEventArgs args) { _drawObject.IsEnabled = false; Geometry[] geometries = new Geometry[] { args.Geometry }; soeUtils.getElevations(geometries); } void soeUtils_GetElevationsEvent(object sender, EventArgs e) { GetElevationsResponse response = (GetElevationsResponse)e; elevationValues.Reset(); Polyline polyline = response.geometries[0] as Polyline; foreach (PointCollection path in polyline.Paths) { elevationValues.AddElevations(path); displayPoints(path); } bottomGrid.Visibility = System.Windows.Visibility.Visible; } private void displayPoints(PointCollection points) { foreach (MapPoint point in points) { Graphic graphic = new Graphic() { Symbol = LayoutRoot.Resources["RedCircleSymbol"] as Symbol, Geometry = point }; GraphicsLayer graphicsLayer = MyMap.Layers["inputsGraphicsLayer"] as GraphicsLayer; graphicsLayer.Graphics.Add(graphic); } } private void ClearButton_Click(object sender, RoutedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["inputsGraphicsLayer"] as GraphicsLayer; graphicsLayer.Graphics.Clear(); bottomGrid.Visibility = System.Windows.Visibility.Collapsed; } } public class ElevationValues { public ObservableCollection<KeyValuePair<int, double>> ValueList { get; private set; } public ObservableCollection<KeyValuePair<string, double>> Info { get; private set; } private int pointCount = -1; private double min = double.MaxValue; private double max = double.MinValue; private int interval = 1; public ElevationValues() { this.ValueList = new ObservableCollection<KeyValuePair<int, double>>(); this.Info = new ObservableCollection<KeyValuePair<string, double>>(); } public void Reset() { this.ValueList.Clear(); this.Info.Clear(); this.pointCount = -1; this.min = double.MaxValue; this.max = double.MinValue; this.interval = 1; this.AddInfo("Min", this.min); this.AddInfo("Max", this.max); this.AddInfo("Interval", this.interval); } public void AddElevations(PointCollection points) { foreach (MapPoint point in points) this.AddElevation(point.Z); } private void AddInfo(string name, double value) { this.Info.Add(new KeyValuePair<string, double>(name, value)); } public void AddElevation(double elevation) { this.ValueList.Add(new KeyValuePair<int, double>(++this.pointCount, elevation)); this.min = Math.Min(this.min, elevation); this.max = Math.Max(this.max, elevation); double range = (this.max - this.min); this.min -= (range * 0.2); this.max += (range * 0.2); this.interval = (int)(this.min + ((this.max - this.min) / 10d)); this.resetInfo(); } private void resetInfo() { this.Info.Clear(); this.AddInfo("Min", this.min); this.AddInfo("Max", this.max); this.AddInfo("Interval", this.interval); } } class ElevationsSOEUtils { public string soeName; public Uri mapServiceUri; public int resourceIndex; private delegate void OperationResultHandler(string jsonResponse, object source); public event EventHandler GetElevationsEvent; private JavaScriptSerializer _jss = new JavaScriptSerializer(); private static ESRI.ArcGIS.Client.Projection.WebMercator _mercator = new ESRI.ArcGIS.Client.Projection.WebMercator(); public ElevationsSOEUtils(string mapServiceUrl, string soeName, int resourceIndex) { this.soeName = soeName; this.mapServiceUri = new Uri(mapServiceUrl); this.resourceIndex = resourceIndex; _jss.RegisterConverters(new JavaScriptConverter[] { new ElevationsSOEResponseConverter(), new WPFGeometryJsonConverter() }); } private void _GetElevationsHandler(string jsonResponse, object source) { GetElevationsResponse response = _jss.Deserialize<GetElevationsResponse>(jsonResponse); if (response != null) { response.source = (Geometry[])source; if (GetElevationsEvent != null) GetElevationsEvent(this, response); } } public void getElevations(Geometry[] geometries) { string jsonGeometries = _jss.Serialize(geometries); string opParams = string.Format(System.Globalization.CultureInfo.InvariantCulture, "geometries={0}&f=json", jsonGeometries); this.invokeOperation("GetElevations", opParams, geometries, this._GetElevationsHandler); } private void invokeOperation(string operationName, string operationParameters, object source, OperationResultHandler operationHandler) { Uri requestUri = new Uri(this.mapServiceUri, string.Format("exts/{0}/ElevationLayers/{1}/{2}?{3}", this.soeName, this.resourceIndex, operationName, operationParameters)); using (WebClient webClient = new WebClient()) { webClient.OpenReadCompleted += (s, a) => { StreamReader sr = new StreamReader(a.Result); string jsonResponse = sr.ReadToEnd(); sr.Close(); operationHandler(jsonResponse, source); }; webClient.OpenReadAsync(requestUri); } } } public class ElevationsSOEResponseConverter : JavaScriptConverter { public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { if (dictionary.ContainsKey("error")) { IDictionary<string, object> error = (IDictionary<string, object>)dictionary["error"]; MessageBox.Show(error["message"].ToString(), error["code"].ToString()); return null; } GetElevationsResponse getElevationsResponse = new GetElevationsResponse(); List<Geometry> geometries = serializer.ConvertToType<List<Geometry>>(dictionary["geometries"]); getElevationsResponse.geometries = geometries.ToArray(); return getElevationsResponse; } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { throw new Exception("The method or operation is not implemented."); } public override IEnumerable<Type> SupportedTypes { get { return new Type[] { typeof(GetElevationsResponse) }; } } } public class GetElevationsResponse : EventArgs { public GetElevationsResponse() { } public GetElevationsResponse(Geometry[] geometries) { this.geometries = geometries; } public Geometry[] source { get; set; } public Geometry[] geometries { get; set; } } public class WPFGeometryJsonConverter : JavaScriptConverter { #region FROM JSON internal MapPoint PartArrayToMapPoint(object partArrayObj) { object[] doubleArrayObj = (object[])((ArrayList)partArrayObj).ToArray(); double[] coords = Array.ConvertAll<object, double>(doubleArrayObj, Convert.ToDouble); MapPoint newPoint = new MapPoint(coords[0], coords[1]); if (coords.Length > 2) newPoint.Z = coords[2]; if (coords.Length > 3) newPoint.M = coords[3]; return newPoint; } internal ESRI.ArcGIS.Client.Geometry.PointCollection PartsArrayToPointColl(object partsArrayObj) { object[] partsArray = (object[])((ArrayList)partsArrayObj).ToArray(); MapPoint[] points = Array.ConvertAll<object, MapPoint>(partsArray, PartArrayToMapPoint); return new ESRI.ArcGIS.Client.Geometry.PointCollection(points); } public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { if (dictionary.ContainsKey("error")) { IDictionary<string, object> error = (IDictionary<string, object>)dictionary["error"]; MessageBox.Show(error["message"].ToString(), error["code"].ToString()); return null; } switch (type.FullName) { case "ESRI.ArcGIS.Client.Geometry.Geometry": if (dictionary.ContainsKey("x")) return this.Deserialize(dictionary, typeof(MapPoint), serializer); if (dictionary.ContainsKey("points")) return this.Deserialize(dictionary, typeof(MultiPoint), serializer); if (dictionary.ContainsKey("paths")) return this.Deserialize(dictionary, typeof(Polyline), serializer); if (dictionary.ContainsKey("rings")) return this.Deserialize(dictionary, typeof(Polygon), serializer); return null; case "ESRI.ArcGIS.Client.Geometry.SpatialReference": SpatialReference spatialReference = new SpatialReference(); if (dictionary.ContainsKey("wkid")) spatialReference.WKID = serializer.ConvertToType<int>(dictionary["wkid"]); if (dictionary.ContainsKey("wkt")) spatialReference.WKT = serializer.ConvertToType<string>(dictionary["WKT"]); return spatialReference; case "ESRI.ArcGIS.Client.Geometry.MapPoint": MapPoint point = new MapPoint(); point.X = serializer.ConvertToType<double>(dictionary["x"]); point.Y = serializer.ConvertToType<double>(dictionary["y"]); if (dictionary.ContainsKey("z")) point.Z = serializer.ConvertToType<double>(dictionary["z"]); if (dictionary.ContainsKey("m")) point.M = serializer.ConvertToType<double>(dictionary["m"]); if (dictionary.ContainsKey("spatialReference")) point.SpatialReference = serializer.ConvertToType<SpatialReference>(dictionary["spatialReference"]); return point; case "ESRI.ArcGIS.Client.Geometry.MultiPoint": MultiPoint multipoint = new MultiPoint(); ArrayList pointsList = serializer.ConvertToType<ArrayList>(dictionary["points"]); MapPoint[] multipointPoints = Array.ConvertAll<object, MapPoint>(pointsList.ToArray(), PartArrayToMapPoint); multipoint.Points = new PointCollection(multipointPoints); if (dictionary.ContainsKey("spatialReference")) multipoint.SpatialReference = serializer.ConvertToType<SpatialReference>(dictionary["spatialReference"]); return multipoint; case "ESRI.ArcGIS.Client.Geometry.Polyline": Polyline polyline = new Polyline(); ArrayList pathsList = serializer.ConvertToType<ArrayList>(dictionary["paths"]); PointCollection[] paths = Array.ConvertAll<object, PointCollection>(pathsList.ToArray(), PartsArrayToPointColl); polyline.Paths = new ObservableCollection<PointCollection>(paths); if (dictionary.ContainsKey("spatialReference")) polyline.SpatialReference = serializer.ConvertToType<SpatialReference>(dictionary["spatialReference"]); return polyline; case "ESRI.ArcGIS.Client.Geometry.Polygon": Polygon polygon = new Polygon(); ArrayList ringsList = serializer.ConvertToType<ArrayList>(dictionary["rings"]); PointCollection[] rings = Array.ConvertAll<object, PointCollection>(ringsList.ToArray(), PartsArrayToPointColl); polygon.Rings = new ObservableCollection<PointCollection>(rings); if (dictionary.ContainsKey("spatialReference")) polygon.SpatialReference = serializer.ConvertToType<SpatialReference>(dictionary["spatialReference"]); return polygon; case "ESRI.ArcGIS.Client.Geometry.Envelope": Envelope envelope = new Envelope(); envelope.XMin = serializer.ConvertToType<double>(dictionary["xmin"]); envelope.YMin = serializer.ConvertToType<double>(dictionary["ymin"]); envelope.XMax = serializer.ConvertToType<double>(dictionary["xmax"]); envelope.YMax = serializer.ConvertToType<double>(dictionary["ymax"]); if (dictionary.ContainsKey("zmin")) envelope.ZMin = serializer.ConvertToType<double>(dictionary["zmin"]); if (dictionary.ContainsKey("zmax")) envelope.ZMax = serializer.ConvertToType<double>(dictionary["zmax"]); if (dictionary.ContainsKey("mmin")) envelope.MMin = serializer.ConvertToType<double>(dictionary["mmin"]); if (dictionary.ContainsKey("mmax")) envelope.MMax = serializer.ConvertToType<double>(dictionary["mmax"]); if (dictionary.ContainsKey("spatialReference")) envelope.SpatialReference = serializer.ConvertToType<SpatialReference>(dictionary["spatialReference"]); return envelope; } return null; } #endregion #region TO JSON internal double[] MapPointToArray(MapPoint mapPoint) { double[] coords = new double[] { mapPoint.X, mapPoint.Y }; if (!double.IsNaN(mapPoint.Z)) coords[coords.Length] = mapPoint.Z; if (!double.IsNaN(mapPoint.M)) coords[coords.Length] = mapPoint.M; return coords; } internal object PointCollectionToObject(PointCollection pointColleciton) { return (object)Array.ConvertAll<MapPoint, double[]>(pointColleciton.ToArray(), MapPointToArray); } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { IDictionary<string, object> jsonDictionary = new Dictionary<string, object>(); if (obj is SpatialReference) { SpatialReference spatialReference = (SpatialReference)obj; jsonDictionary.Add("wkid", spatialReference.WKID); if (!string.IsNullOrEmpty(spatialReference.WKT)) jsonDictionary.Add("wkt", spatialReference.WKT); } else if (obj is MapPoint) { MapPoint mapPoint = (MapPoint)obj; jsonDictionary.Add("x", mapPoint.X); jsonDictionary.Add("y", mapPoint.Y); if (!double.IsNaN(mapPoint.Z)) jsonDictionary.Add("z", mapPoint.Z); if (!double.IsNaN(mapPoint.M)) jsonDictionary.Add("m", mapPoint.M); if (mapPoint.SpatialReference != null) jsonDictionary.Add("spatialReference", mapPoint.SpatialReference); } else if (obj is MultiPoint) { MultiPoint multipoint = (MultiPoint)obj; if (multipoint.SpatialReference != null) jsonDictionary.Add("spatialReference", multipoint.SpatialReference); jsonDictionary.Add("hasZ", multipoint.HasZ); jsonDictionary.Add("hasM", multipoint.HasM); object points = PointCollectionToObject(multipoint.Points); jsonDictionary.Add("points", points); } else if (obj is Polyline) { Polyline polyline = (Polyline)obj; if (polyline.SpatialReference != null) jsonDictionary.Add("spatialReference", polyline.SpatialReference); jsonDictionary.Add("hasZ", polyline.HasZ); jsonDictionary.Add("hasM", polyline.HasM); object[] paths = Array.ConvertAll<PointCollection, object>(polyline.Paths.ToArray(), PointCollectionToObject); jsonDictionary.Add("paths", paths); } else if (obj is Polygon) { Polygon polygon = (Polygon)obj; if (polygon.SpatialReference != null) jsonDictionary.Add("spatialReference", polygon.SpatialReference); jsonDictionary.Add("hasZ", polygon.HasZ); jsonDictionary.Add("hasM", polygon.HasM); object[] rings = Array.ConvertAll<PointCollection, object>(polygon.Rings.ToArray(), PointCollectionToObject); jsonDictionary.Add("rings", rings); } else if (obj is Envelope) { Envelope envelope = (Envelope)obj; if (envelope.SpatialReference != null) jsonDictionary.Add("spatialReference", envelope.SpatialReference); jsonDictionary.Add("xmin", envelope.XMin); jsonDictionary.Add("ymin", envelope.YMin); jsonDictionary.Add("xmax", envelope.XMax); jsonDictionary.Add("ymax", envelope.YMax); if (!double.IsNaN(envelope.ZMin)) jsonDictionary.Add("zmin", envelope.ZMin); if (!double.IsNaN(envelope.ZMax)) jsonDictionary.Add("zmax", envelope.ZMax); if (!double.IsNaN(envelope.MMin)) jsonDictionary.Add("mmin", envelope.MMin); if (!double.IsNaN(envelope.MMax)) jsonDictionary.Add("mmax", envelope.MMax); } return jsonDictionary; } #endregion public override IEnumerable<Type> SupportedTypes { get { return new Type[] { typeof(ESRI.ArcGIS.Client.Geometry.Geometry), typeof(ESRI.ArcGIS.Client.Geometry.SpatialReference), typeof(ESRI.ArcGIS.Client.Geometry.MapPoint), typeof(ESRI.ArcGIS.Client.Geometry.MultiPoint), typeof(ESRI.ArcGIS.Client.Geometry.Polyline), typeof(ESRI.ArcGIS.Client.Geometry.Polygon), typeof(ESRI.ArcGIS.Client.Geometry.Envelope)}; } } } }
Imports System.Collections.Generic Imports System.Linq Imports System.Windows Imports System.Windows.Controls Imports System.Windows.Documents Imports System.Web.Script.Serialization Imports ESRI.ArcGIS.Client.Geometry Imports System.Collections Imports System.Collections.ObjectModel Imports System.Net Imports System.IO Imports ESRI.ArcGIS.Client Imports ESRI.ArcGIS.Client.Symbols Namespace ArcGISWPFSDK Partial Public Class SOEElevationProfileViewer Inherits UserControl Private Shared ELEVATION_MAPSERVICE_URL As String = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Elevation/WorldElevations/MapServer/" Private Shared ELEVATION_SOE_NAME As String = "ElevationsSOE_NET" Private Shared ELEVATION_RESOURCE_INDEX As Integer = 0 Private _drawObject As Draw Private currentSymbol As Symbol Private soeUtils As ElevationsSOEUtils Private elevationValues As ElevationValues Public Sub New() InitializeComponent() soeUtils = New ElevationsSOEUtils(ELEVATION_MAPSERVICE_URL, ELEVATION_SOE_NAME, ELEVATION_RESOURCE_INDEX) AddHandler soeUtils.GetElevationsEvent, New EventHandler(AddressOf soeUtils_GetElevationsEvent) _drawObject = New Draw(MyMap) With { _ .FillSymbol = TryCast(LayoutRoot.Resources("GreenFillSymbol"), FillSymbol), _ .LineSymbol = TryCast(LayoutRoot.Resources("BlueLineSymbol"), LineSymbol) _ } AddHandler _drawObject.DrawBegin, AddressOf MyDrawObject_OnDrawBegin AddHandler _drawObject.DrawComplete, AddressOf MyDrawObject_OnDrawComplete elevationValues = New ElevationValues() profileChart.DataContext = elevationValues End Sub Private Sub GetProfileButton_Click(sender As Object, e As RoutedEventArgs) _drawObject.IsEnabled = False currentSymbol = TryCast(LayoutRoot.Resources("BlueLineSymbol"), Symbol) _drawObject.DrawMode = DrawMode.Polyline _drawObject.IsEnabled = True End Sub Private Sub MyDrawObject_OnDrawBegin(sender As Object, args As EventArgs) Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("inputsGraphicsLayer"), GraphicsLayer) graphicsLayer.Graphics.Clear() End Sub Private Sub MyDrawObject_OnDrawComplete(sender As Object, args As DrawEventArgs) _drawObject.IsEnabled = False Dim geometries As Geometry() = New Geometry() {args.Geometry} soeUtils.getElevations(geometries) End Sub Private Sub soeUtils_GetElevationsEvent(sender As Object, e As EventArgs) Dim response As GetElevationsResponse = DirectCast(e, GetElevationsResponse) elevationValues.Reset() Dim polyline As Polyline = TryCast(response.geometries(0), Polyline) For Each path As PointCollection In polyline.Paths elevationValues.AddElevations(path) displayPoints(path) Next bottomGrid.Visibility = System.Windows.Visibility.Visible End Sub Private Sub displayPoints(points As PointCollection) For Each point As MapPoint In points Dim graphic As New Graphic() With { _ .Symbol = TryCast(LayoutRoot.Resources("RedCircleSymbol"), Symbol), _ .Geometry = point _ } Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("inputsGraphicsLayer"), GraphicsLayer) graphicsLayer.Graphics.Add(graphic) Next End Sub Private Sub ClearButton_Click(sender As Object, e As RoutedEventArgs) Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("inputsGraphicsLayer"), GraphicsLayer) graphicsLayer.Graphics.Clear() bottomGrid.Visibility = System.Windows.Visibility.Collapsed End Sub End Class Public Class ElevationValues Public Property ValueList() As ObservableCollection(Of KeyValuePair(Of Integer, Double)) Get Return m_ValueList End Get Private Set(value As ObservableCollection(Of KeyValuePair(Of Integer, Double))) m_ValueList = Value End Set End Property Private m_ValueList As ObservableCollection(Of KeyValuePair(Of Integer, Double)) Public Property Info() As ObservableCollection(Of KeyValuePair(Of String, Double)) Get Return m_Info End Get Private Set(value As ObservableCollection(Of KeyValuePair(Of String, Double))) m_Info = Value End Set End Property Private m_Info As ObservableCollection(Of KeyValuePair(Of String, Double)) Private pointCount As Integer = -1 Private min As Double = Double.MaxValue Private max As Double = Double.MinValue Private interval As Integer = 1 Public Sub New() Me.ValueList = New ObservableCollection(Of KeyValuePair(Of Integer, Double))() Me.Info = New ObservableCollection(Of KeyValuePair(Of String, Double))() End Sub Public Sub Reset() Me.ValueList.Clear() Me.Info.Clear() Me.pointCount = -1 Me.min = Double.MaxValue Me.max = Double.MinValue Me.interval = 1 Me.AddInfo("Min", Me.min) Me.AddInfo("Max", Me.max) Me.AddInfo("Interval", Me.interval) End Sub Public Sub AddElevations(points As PointCollection) For Each point As MapPoint In points Me.AddElevation(point.Z) Next End Sub Private Sub AddInfo(name As String, value As Double) Me.Info.Add(New KeyValuePair(Of String, Double)(name, value)) End Sub Public Sub AddElevation(elevation As Double) Me.ValueList.Add(New KeyValuePair(Of Integer, Double)(System.Threading.Interlocked.Increment(Me.pointCount), elevation)) Me.min = Math.Min(Me.min, elevation) Me.max = Math.Max(Me.max, elevation) Dim range As Double = (Me.max - Me.min) Me.min -= (range * 0.2) Me.max += (range * 0.2) Me.interval = CInt(Math.Truncate(Me.min + ((Me.max - Me.min) / 10.0))) Me.resetInfo() End Sub Private Sub resetInfo() Me.Info.Clear() Me.AddInfo("Min", Me.min) Me.AddInfo("Max", Me.max) Me.AddInfo("Interval", Me.interval) End Sub End Class Class ElevationsSOEUtils Public soeName As String Public mapServiceUri As Uri Public resourceIndex As Integer Private Delegate Sub OperationResultHandler(jsonResponse As String, source As Object) Public Event GetElevationsEvent As EventHandler Private _jss As New JavaScriptSerializer() Private Shared _mercator As New ESRI.ArcGIS.Client.Projection.WebMercator() Public Sub New(mapServiceUrl As String, soeName As String, resourceIndex As Integer) Me.soeName = soeName Me.mapServiceUri = New Uri(mapServiceUrl) Me.resourceIndex = resourceIndex _jss.RegisterConverters(New JavaScriptConverter() {New ElevationsSOEResponseConverter(), New WPFGeometryJsonConverter()}) End Sub Private Sub _GetElevationsHandler(jsonResponse As String, source As Object) Dim response As GetElevationsResponse = _jss.Deserialize(Of GetElevationsResponse)(jsonResponse) If response IsNot Nothing Then response.source = DirectCast(source, Geometry()) RaiseEvent GetElevationsEvent(Me, response) End If End Sub Public Sub getElevations(geometries As Geometry()) Dim jsonGeometries As String = _jss.Serialize(geometries) Dim opParams As String = String.Format(System.Globalization.CultureInfo.InvariantCulture, "geometries={0}&f=json", jsonGeometries) Me.invokeOperation("GetElevations", opParams, geometries, AddressOf Me._GetElevationsHandler) End Sub Private Sub invokeOperation(operationName As String, operationParameters As String, source As Object, operationHandler As OperationResultHandler) Dim requestUri As New Uri(Me.mapServiceUri, String.Format("exts/{0}/ElevationLayers/{1}/{2}?{3}", Me.soeName, Me.resourceIndex, operationName, operationParameters)) Using webClient As New WebClient() AddHandler webClient.OpenReadCompleted, Function(s, a) Dim sr As New StreamReader(a.Result) Dim jsonResponse As String = sr.ReadToEnd() sr.Close() operationHandler(jsonResponse, source) End Function webClient.OpenReadAsync(requestUri) End Using End Sub End Class Public Class ElevationsSOEResponseConverter Inherits JavaScriptConverter Public Overrides Function Deserialize(dictionary As IDictionary(Of String, Object), type As Type, serializer As JavaScriptSerializer) As Object If dictionary.ContainsKey("error") Then Dim [error] As IDictionary(Of String, Object) = DirectCast(dictionary("error"), IDictionary(Of String, Object)) MessageBox.Show([error]("message").ToString(), [error]("code").ToString()) Return Nothing End If Dim getElevationsResponse As New GetElevationsResponse() Dim geometries As List(Of Geometry) = serializer.ConvertToType(Of List(Of Geometry))(dictionary("geometries")) getElevationsResponse.geometries = geometries.ToArray() Return getElevationsResponse End Function Public Overrides Function Serialize(obj As Object, serializer As JavaScriptSerializer) As IDictionary(Of String, Object) Throw New Exception("The method or operation is not implemented.") End Function Public Overrides ReadOnly Property SupportedTypes() As IEnumerable(Of Type) Get Return New Type() {GetType(GetElevationsResponse)} End Get End Property End Class Public Class GetElevationsResponse Inherits EventArgs Public Sub New() End Sub Public Sub New(geometries As Geometry()) Me.geometries = geometries End Sub Public Property source() As Geometry() Get Return m_source End Get Set(value As Geometry()) m_source = Value End Set End Property Private m_source As Geometry() Public Property geometries() As Geometry() Get Return m_geometries End Get Set(value As Geometry()) m_geometries = Value End Set End Property Private m_geometries As Geometry() End Class Public Class WPFGeometryJsonConverter Inherits JavaScriptConverter #Region "FROM JSON" Friend Function PartArrayToMapPoint(partArrayObj As Object) As MapPoint Dim doubleArrayObj As Object() = DirectCast(DirectCast(partArrayObj, ArrayList).ToArray(), Object()) Dim coords As Double() = Array.ConvertAll(Of Object, Double)(doubleArrayObj, AddressOf Convert.ToDouble) Dim newPoint As New MapPoint(coords(0), coords(1)) If coords.Length > 2 Then newPoint.Z = coords(2) End If If coords.Length > 3 Then newPoint.M = coords(3) End If Return newPoint End Function Friend Function PartsArrayToPointColl(partsArrayObj As Object) As ESRI.ArcGIS.Client.Geometry.PointCollection Dim partsArray As Object() = DirectCast(DirectCast(partsArrayObj, ArrayList).ToArray(), Object()) Dim points As MapPoint() = Array.ConvertAll(Of Object, MapPoint)(partsArray, AddressOf PartArrayToMapPoint) Return New ESRI.ArcGIS.Client.Geometry.PointCollection(points) End Function Public Overrides Function Deserialize(dictionary As IDictionary(Of String, Object), type As Type, serializer As JavaScriptSerializer) As Object If dictionary.ContainsKey("error") Then Dim [error] As IDictionary(Of String, Object) = DirectCast(dictionary("error"), IDictionary(Of String, Object)) MessageBox.Show([error]("message").ToString(), [error]("code").ToString()) Return Nothing End If Select Case type.FullName Case "ESRI.ArcGIS.Client.Geometry.Geometry" If dictionary.ContainsKey("x") Then Return Me.Deserialize(dictionary, GetType(MapPoint), serializer) End If If dictionary.ContainsKey("points") Then Return Me.Deserialize(dictionary, GetType(MultiPoint), serializer) End If If dictionary.ContainsKey("paths") Then Return Me.Deserialize(dictionary, GetType(Polyline), serializer) End If If dictionary.ContainsKey("rings") Then Return Me.Deserialize(dictionary, GetType(Polygon), serializer) End If Return Nothing Case "ESRI.ArcGIS.Client.Geometry.SpatialReference" Dim spatialReference As New SpatialReference() If dictionary.ContainsKey("wkid") Then spatialReference.WKID = serializer.ConvertToType(Of Integer)(dictionary("wkid")) End If If dictionary.ContainsKey("wkt") Then spatialReference.WKT = serializer.ConvertToType(Of String)(dictionary("WKT")) End If Return spatialReference Case "ESRI.ArcGIS.Client.Geometry.MapPoint" Dim point As New MapPoint() point.X = serializer.ConvertToType(Of Double)(dictionary("x")) point.Y = serializer.ConvertToType(Of Double)(dictionary("y")) If dictionary.ContainsKey("z") Then point.Z = serializer.ConvertToType(Of Double)(dictionary("z")) End If If dictionary.ContainsKey("m") Then point.M = serializer.ConvertToType(Of Double)(dictionary("m")) End If If dictionary.ContainsKey("spatialReference") Then point.SpatialReference = serializer.ConvertToType(Of SpatialReference)(dictionary("spatialReference")) End If Return point Case "ESRI.ArcGIS.Client.Geometry.MultiPoint" Dim multipoint As New MultiPoint() Dim pointsList As ArrayList = serializer.ConvertToType(Of ArrayList)(dictionary("points")) Dim multipointPoints As MapPoint() = Array.ConvertAll(Of Object, MapPoint)(pointsList.ToArray(), AddressOf PartArrayToMapPoint) multipoint.Points = New PointCollection(multipointPoints) If dictionary.ContainsKey("spatialReference") Then multipoint.SpatialReference = serializer.ConvertToType(Of SpatialReference)(dictionary("spatialReference")) End If Return multipoint Case "ESRI.ArcGIS.Client.Geometry.Polyline" Dim polyline As New Polyline() Dim pathsList As ArrayList = serializer.ConvertToType(Of ArrayList)(dictionary("paths")) Dim paths As PointCollection() = Array.ConvertAll(Of Object, PointCollection)(pathsList.ToArray(), AddressOf PartsArrayToPointColl) polyline.Paths = New ObservableCollection(Of PointCollection)(paths) If dictionary.ContainsKey("spatialReference") Then polyline.SpatialReference = serializer.ConvertToType(Of SpatialReference)(dictionary("spatialReference")) End If Return polyline Case "ESRI.ArcGIS.Client.Geometry.Polygon" Dim polygon As New Polygon() Dim ringsList As ArrayList = serializer.ConvertToType(Of ArrayList)(dictionary("rings")) Dim rings As PointCollection() = Array.ConvertAll(Of Object, PointCollection)(ringsList.ToArray(), AddressOf PartsArrayToPointColl) polygon.Rings = New ObservableCollection(Of PointCollection)(rings) If dictionary.ContainsKey("spatialReference") Then polygon.SpatialReference = serializer.ConvertToType(Of SpatialReference)(dictionary("spatialReference")) End If Return polygon Case "ESRI.ArcGIS.Client.Geometry.Envelope" Dim envelope As New Envelope() envelope.XMin = serializer.ConvertToType(Of Double)(dictionary("xmin")) envelope.YMin = serializer.ConvertToType(Of Double)(dictionary("ymin")) envelope.XMax = serializer.ConvertToType(Of Double)(dictionary("xmax")) envelope.YMax = serializer.ConvertToType(Of Double)(dictionary("ymax")) If dictionary.ContainsKey("zmin") Then envelope.ZMin = serializer.ConvertToType(Of Double)(dictionary("zmin")) End If If dictionary.ContainsKey("zmax") Then envelope.ZMax = serializer.ConvertToType(Of Double)(dictionary("zmax")) End If If dictionary.ContainsKey("mmin") Then envelope.MMin = serializer.ConvertToType(Of Double)(dictionary("mmin")) End If If dictionary.ContainsKey("mmax") Then envelope.MMax = serializer.ConvertToType(Of Double)(dictionary("mmax")) End If If dictionary.ContainsKey("spatialReference") Then envelope.SpatialReference = serializer.ConvertToType(Of SpatialReference)(dictionary("spatialReference")) End If Return envelope End Select Return Nothing End Function #End Region #Region "TO JSON" Friend Function MapPointToArray(mapPoint As MapPoint) As Double() Dim coords As Double() = New Double() {mapPoint.X, mapPoint.Y} If Not Double.IsNaN(mapPoint.Z) Then coords(coords.Length) = mapPoint.Z End If If Not Double.IsNaN(mapPoint.M) Then coords(coords.Length) = mapPoint.M End If Return coords End Function Friend Function PointCollectionToObject(pointColleciton As PointCollection) As Object Return DirectCast(Array.ConvertAll(Of MapPoint, Double())(pointColleciton.ToArray(), AddressOf MapPointToArray), Object) End Function Public Overrides Function Serialize(obj As Object, serializer As JavaScriptSerializer) As IDictionary(Of String, Object) Dim jsonDictionary As IDictionary(Of String, Object) = New Dictionary(Of String, Object)() If TypeOf obj Is SpatialReference Then Dim spatialReference As SpatialReference = DirectCast(obj, SpatialReference) jsonDictionary.Add("wkid", spatialReference.WKID) If Not String.IsNullOrEmpty(spatialReference.WKT) Then jsonDictionary.Add("wkt", spatialReference.WKT) End If ElseIf TypeOf obj Is MapPoint Then Dim mapPoint As MapPoint = DirectCast(obj, MapPoint) jsonDictionary.Add("x", mapPoint.X) jsonDictionary.Add("y", mapPoint.Y) If Not Double.IsNaN(mapPoint.Z) Then jsonDictionary.Add("z", mapPoint.Z) End If If Not Double.IsNaN(mapPoint.M) Then jsonDictionary.Add("m", mapPoint.M) End If If mapPoint.SpatialReference IsNot Nothing Then jsonDictionary.Add("spatialReference", mapPoint.SpatialReference) End If ElseIf TypeOf obj Is MultiPoint Then Dim multipoint As MultiPoint = DirectCast(obj, MultiPoint) If multipoint.SpatialReference IsNot Nothing Then jsonDictionary.Add("spatialReference", multipoint.SpatialReference) End If jsonDictionary.Add("hasZ", multipoint.HasZ) jsonDictionary.Add("hasM", multipoint.HasM) Dim points As Object = PointCollectionToObject(multipoint.Points) jsonDictionary.Add("points", points) ElseIf TypeOf obj Is Polyline Then Dim polyline As Polyline = DirectCast(obj, Polyline) If polyline.SpatialReference IsNot Nothing Then jsonDictionary.Add("spatialReference", polyline.SpatialReference) End If jsonDictionary.Add("hasZ", polyline.HasZ) jsonDictionary.Add("hasM", polyline.HasM) Dim paths As Object() = Array.ConvertAll(Of PointCollection, Object)(polyline.Paths.ToArray(), AddressOf PointCollectionToObject) jsonDictionary.Add("paths", paths) ElseIf TypeOf obj Is Polygon Then Dim polygon As Polygon = DirectCast(obj, Polygon) If polygon.SpatialReference IsNot Nothing Then jsonDictionary.Add("spatialReference", polygon.SpatialReference) End If jsonDictionary.Add("hasZ", polygon.HasZ) jsonDictionary.Add("hasM", polygon.HasM) Dim rings As Object() = Array.ConvertAll(Of PointCollection, Object)(polygon.Rings.ToArray(), AddressOf PointCollectionToObject) jsonDictionary.Add("rings", rings) ElseIf TypeOf obj Is Envelope Then Dim envelope As Envelope = DirectCast(obj, Envelope) If envelope.SpatialReference IsNot Nothing Then jsonDictionary.Add("spatialReference", envelope.SpatialReference) End If jsonDictionary.Add("xmin", envelope.XMin) jsonDictionary.Add("ymin", envelope.YMin) jsonDictionary.Add("xmax", envelope.XMax) jsonDictionary.Add("ymax", envelope.YMax) If Not Double.IsNaN(envelope.ZMin) Then jsonDictionary.Add("zmin", envelope.ZMin) End If If Not Double.IsNaN(envelope.ZMax) Then jsonDictionary.Add("zmax", envelope.ZMax) End If If Not Double.IsNaN(envelope.MMin) Then jsonDictionary.Add("mmin", envelope.MMin) End If If Not Double.IsNaN(envelope.MMax) Then jsonDictionary.Add("mmax", envelope.MMax) End If End If Return jsonDictionary End Function #End Region Public Overrides ReadOnly Property SupportedTypes() As IEnumerable(Of Type) Get Return New Type() {GetType(ESRI.ArcGIS.Client.Geometry.Geometry), GetType(ESRI.ArcGIS.Client.Geometry.SpatialReference), GetType(ESRI.ArcGIS.Client.Geometry.MapPoint), GetType(ESRI.ArcGIS.Client.Geometry.MultiPoint), GetType(ESRI.ArcGIS.Client.Geometry.Polyline), GetType(ESRI.ArcGIS.Client.Geometry.Polygon), _ GetType(ESRI.ArcGIS.Client.Geometry.Envelope)} End Get End Property End Class End Namespace
Copyright © 1995-2014 Esri. All rights reserved.
5/16/2014