Wednesday, May 19, 2010

Moveable graphics with ESRI’s ArcGIS API for Silverlight

image

By default, graphics added to an ESRI Silverlight map are static.  This post will demonstrate how to add map behavior so that graphics can be repositioned with regular mouse interaction.  In some situations, providing moveable graphics is a more intuitive method of achieving user interaction.  For example, you could have a moveable start and end pushpin in a routing application.

In this sample, the web application will create ten Elvis symbols at random locations.  Whenever a graphic is added to the map, the application will begin for listen for mouse events (on the graphic).  When there is a LeftMouseButtonDown event on a graphic, a DragGraphic object is created.  This class stores a reference to the selected graphic and the original position of the graphic and mouse cursor.  If the mouse moves again the graphic or map, information from the DragGraphic class is used to update the selected graphic’s position.

To view a live sample, please click the link below.
http://maps.esri.com/sldemos/mg/default.html

<UserControl
    x:Class="MoveableGraphicsSample.MainPage"
    xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
    xmlns:esriSymbols="clr-namespace:ESRI.ArcGIS.Client.Symbols;
assembly=ESRI.ArcGIS.Client"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid Background="White"> <esri:Map Name="Map"> <esri:Map.Resources> <esriSymbols:MarkerSymbol x:Key="Elvis"> <esriSymbols:MarkerSymbol.ControlTemplate> <ControlTemplate> <Grid> <Ellipse Height="50" Width="50"
Cursor="Hand" Stroke
="White"
StrokeThickness
="2"> <Ellipse.Fill> <!-- see http://commons.wikimedia.org/wiki/File:Elvis_Presley_1970.jpg –> <ImageBrush Stretch="UniformToFill" ImageSource="http://upload.wikimedia.org/wikipedia/commons/8/82/
Elvis_Presley_1970.jpg" /> </
Ellipse.Fill
> <Ellipse.Effect> <DropShadowEffect /> </Ellipse.Effect> <Ellipse.RenderTransform> <TranslateTransform X="-25"
Y
="-25"/> </Ellipse.RenderTransform> </Ellipse> </Grid> </ControlTemplate> </esriSymbols:MarkerSymbol.ControlTemplate> </esriSymbols:MarkerSymbol> </esri:Map.Resources> <esri:Map.Layers> <esri:ArcGISTiledMapServiceLayer
Url
="http://server.arcgisonline.com/ArcGIS/rest/services/
World_Topo_Map/MapServer"/> <
esri:GraphicsLayer
/> </esri:Map.Layers> </esri:Map> </Grid> </UserControl>

…and the code behind….

using System;
using System.Collections.Specialized;
using System.Windows.Controls;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Symbols;

namespace MoveableGraphicsSample {
    public partial class MainPage : UserControl {
        private DragGraphic _dragGraphic = null;
        private Random _random = new Random();

        public MainPage() {
            InitializeComponent();

            // Get layers
            ArcGISTiledMapServiceLayer topoLayer = this.Map.Layers[0]
as ArcGISTiledMapServiceLayer; GraphicsLayer graphicsLayer = this.Map.Layers[1]
as GraphicsLayer;
// Wait until the map service layer has loaded and initialized topoLayer.Initialized += (a, b) => { for (int i = 0; i < 10; i++) { graphicsLayer.Graphics.Add( new Graphic() { // Create a random location Geometry = new MapPoint() { X = topoLayer.InitialExtent.XMin +
this._random.NextDouble() *
(topoLayer.InitialExtent.XMax -
topoLayer.InitialExtent.XMin), Y = topoLayer.InitialExtent.YMin +
this._random.NextDouble() *
(topoLayer.InitialExtent.YMax -
topoLayer.InitialExtent.YMin) },
// Use the markersymbol defined in the resource Symbol = this.Map.Resources["Elvis"]
as
MarkerSymbol } ); } }; graphicsLayer.Graphics.CollectionChanged += (a, b) => { // Exit if not added graphic if (b.Action != NotifyCollectionChangedAction.Add) { return;} // Get added graphic Graphic graphic = b.NewItems[0] as Graphic; // When the graphic is clicked, store the current state graphic.MouseLeftButtonDown += (sender, e) => { this._dragGraphic = new DragGraphic() { Graphic = graphic, GraphicOrigin = graphic.Geometry as MapPoint, MouseOrigin = this.Map.ScreenToMap(e.GetPosition(null)) }; e.Handled = true; }; // When the mouse is moved update the graphic's position graphic.MouseMove += (sender, e) => { if (this._dragGraphic == null) { return; } this._dragGraphic.Graphic.Geometry = new MapPoint() { X = this._dragGraphic.GraphicOrigin.X +
(this.Map.ScreenToMap(e.GetPosition(null)).X -
this._dragGraphic.MouseOrigin.X), Y = this._dragGraphic.GraphicOrigin.Y +
(this.Map.ScreenToMap(e.GetPosition(null)).Y -
this._dragGraphic.MouseOrigin.Y) }; };
// Clear the seleced graphic on mouse up graphic.MouseLeftButtonUp += (sender, e) => { this._dragGraphic = null; }; }; // Adjust the selected graphics position if the mouse moves this.Map.MouseMove += (sender, e) => { if (this._dragGraphic == null) { return; } this._dragGraphic.Graphic.Geometry = new MapPoint() { X = this._dragGraphic.GraphicOrigin.X +
(this.Map.ScreenToMap(e.GetPosition(null)).X -
this._dragGraphic.MouseOrigin.X), Y = this._dragGraphic.GraphicOrigin.Y +
(this.Map.ScreenToMap(e.GetPosition(null)).Y -
this._dragGraphic.MouseOrigin.Y) }; }; } } public class DragGraphic { public Graphic Graphic { get; set; } public MapPoint MouseOrigin { get; set; } public MapPoint GraphicOrigin { get; set; } } }

Tuesday, May 18, 2010

Cross Country Mobility for Silverlight

Almost a year ago, ESRI’s Applications Prototype Lab published a video demonstrating a cross country mobility (or CCM) application for Microsoft’s Surface device.  This application is now available as a public Silverlight-based web application.  Click here to launch the web application or you can watch the embedded video above.

How to run the demonstration:

  1. Open a web browser to:
    http://maps.esri.com/sldemos/ccm/default.html
    (you may be prompted to install Silverlight 4)
  2. Move the target icon anywhere on the map.  This is the destination of the three flagged icons.
  3. Move the three flagged icons to any location on the map.  These icons represent three vehicles that are seeking the most efficient route to the target icon.
  4. Click the Weighting button to adjust the parameters for the cost surface.  In this menu you can refine the definition of “cost” for each pixel on the map.  Moving a slider to the left indicates that the category or sub-category is less expensive (in time, money, fuel or some other resource).  Similarly, moving a slider to the right indicates that category or sub-category is more expensive or costly.
  5. Click the Submit button to send the weighting parameters to the server.  The server will create and return a cost surface shaded from green to red.  A green area represents areas that are cheap to traverse whereas red areas are more expensive.  Unshaded areas are “no-go” areas that cannot be traversed whatsoever such as water bodies (as defined in the weighting menu above).
  6. Click the Show/Hide Surface button to hide the cost surface (optional),
  7. Click the Path button to display best path, that is,the path of least cost (in fuel, time, money etc).
  8. Move the flagged icons and click the Path button to repeat the best path analysis.  You cannot change the position of the target icon at this stage because the cost surface has been optimized with respect to the destination.  To change the destination click the Reset button to start over.
  9. Before moving to the next step move the vertical slider on the right hand slide so that the map only displays satellite imagery.  This will make the results of the next step a little easier to visualize.
  10. Click the Corridor button.  Rather than showing just the ideal routing solution, the server will now calculate the top three percentile solution set.  The result is a multi-shaded corridor with the lightest shade represent the top three percentile and the darker shade the top one percentile.  This type of analysis is useful in highlighting choke points, that is, locations where people and vehicle must pass through.  Conversely it is a useful tool to locate possible ambush location.

Monday, May 17, 2010

Augmented Reality and ESRI’s ArcGIS API for Silverlight

   

The lab has just completed a prototype that combines ESRI’s ArcGIS API for Silverlight with the open source Silverlight Augmented Reality Toolkit.

The toolkit allows developers to detect the spatial orientation of a predefined marker.  The lab used the orientation information to overlay a map from ESRI’s ArcGIS API for Silverlight.  As shown in the video, the map is fully functional even with the perspective distortion.

The demonstration starts with the user browsing a default basemap from ESRI’s resource center and then performs a search of GeoEye imagery in New Zealand.  All imagery is tagged with sensor information such as the capture date, percentage cloud cover and satellite position.  In the video, this information is used to order and then offset overlapping imagery.  This effect is useful to quickly find imagery based on specific criteria, for example, find the newest imagery with the least amount of cloud cover.

Finally, why not try this demonstration yourself?  You will need a computer with a webcam.  Click here to start the Augmented Reality web application and here to download and print the marker symbol.