Skip To Content ArcGIS for Developers Sign In Dashboard

ArcGIS Runtime SDK for .NET

Geodesic operations

This code sample is available for these platforms:
View Sample on GitHub

This sample demonstrates how to perform geodesic operations on geometries using the GeometryEngine. Geodesic calculations take into account the curvature of the Earth, while planar calculations are based on a 2D Cartesian plane.

screenshot

Use case

Visualizing flight paths between cities is a common example of a geodesic operation--notice the lines are not straight, but curved. A geodesic distance must be calculated to get an accurate real world distance between two points on a 2D map.

How to use the sample

  1. Click anywhere on the map. A line graphic will display the geodesic line between the two points. In addition, text that indicates the geodesic distance between the two points will be updated.
  2. Click elsewhere and a new line will be created.

How it works

  1. A Point is created in New York City and displayed as a Graphic.
  2. When a click occurs on the MapView, a new Point is obtained from the mouse click. This Point is added as a Graphic.
  3. A Polyline is created with the two Point objects.
  4. GeometryEngine.DensifyGeodetic is executed by passing in the Polyline object, and the returned Geometry is added as a Graphic.
  5. GeometryEngine.LengthGeodetic is executed by passing in the two Point objects, and the returned number is displayed on the screen.

Relevant API

  • GeometryEngine.DensifyGeodetic
  • GeometryEngine.LengthGeodetic

Tags

GeometryEngine, densify, distance, geodesic, geodetic

Sample Code

<UserControl
    x:Class="ArcGISRuntime.UWP.Samples.GeodesicOperations.GeodesicOperations"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="using:Esri.ArcGISRuntime.UI.Controls">
    <Grid>
        <controls:MapView x:Name="MyMapView" />
        <Border Style="{StaticResource BorderStyle}">
            <StackPanel>
                <TextBlock x:Name="ResultsLabel"
                           Text="Tap to set an end point."
                           FontWeight="SemiBold"
                           TextAlignment="Center" />
            </StackPanel>
        </Border>
    </Grid>
</UserControl>
// Copyright 2018 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.UI.Controls;

namespace ArcGISRuntime.UWP.Samples.GeodesicOperations
{
    [ArcGISRuntime.Samples.Shared.Attributes.Sample(
        "Geodesic operations",
        "Geometry",
        "This sample demonstrates how to use the Geometry engine to calculate a geodesic path between two points and measure its distance.",
        "Tap on the map to set the end point of a path from New York City. The geodesic path and geodesic distance will be displayed.")]
    public partial class GeodesicOperations
    {
        // Hold references to the graphics.
        private Graphic _startLocationGraphic;
        private Graphic _endLocationGraphic;
        private Graphic _pathGraphic;

        public GeodesicOperations()
        {
            InitializeComponent();

            // Setup the control references and execute initialization.
            Initialize();
        }

        private void Initialize()
        {
            MyMapView.Map = new Map(Basemap.CreateImagery());

            // Create the graphics overlay and add it to the map view.
            GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
            MyMapView.GraphicsOverlays.Add(graphicsOverlay);

            // Add a graphic at JFK to serve as the origin.
            MapPoint start = new MapPoint(-73.7781, 40.6413, SpatialReferences.Wgs84);
            SimpleMarkerSymbol startMarker = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, System.Drawing.Color.Blue, 10);
            _startLocationGraphic = new Graphic(start, startMarker);

            // Create the graphic for the destination.
            _endLocationGraphic = new Graphic
            {
                Symbol = startMarker
            };

            // Create the graphic for the path.
            _pathGraphic = new Graphic
            {
                Symbol = new SimpleLineSymbol(SimpleLineSymbolStyle.Dash, System.Drawing.Color.Blue, 5)
            };

            // Add the graphics to the overlay.
            graphicsOverlay.Graphics.Add(_startLocationGraphic);
            graphicsOverlay.Graphics.Add(_endLocationGraphic);
            graphicsOverlay.Graphics.Add(_pathGraphic);

            // Update end location when the user taps.
            MyMapView.GeoViewTapped += MyMapViewOnGeoViewTapped;
        }

        private void MyMapViewOnGeoViewTapped(object sender, GeoViewInputEventArgs geoViewInputEventArgs)
        {
            // Get the tapped point, projected to WGS84.
            MapPoint destination = (MapPoint)GeometryEngine.Project(geoViewInputEventArgs.Location, SpatialReferences.Wgs84);

            // Update the destination graphic.
            _endLocationGraphic.Geometry = destination;

            // Get the points that define the route polyline.
            PointCollection polylinePoints = new PointCollection(SpatialReferences.Wgs84)
            {
                (MapPoint)_startLocationGraphic.Geometry,
                destination
            };

            // Create the polyline for the two points.
            Polyline routeLine = new Polyline(polylinePoints);

            // Densify the polyline to show the geodesic curve.
            Geometry pathGeometry = GeometryEngine.DensifyGeodetic(routeLine, 1, LinearUnits.Kilometers, GeodeticCurveType.Geodesic);

            // Apply the curved line to the path graphic.
            _pathGraphic.Geometry = pathGeometry;

            // Calculate and show the distance.
            double distance = GeometryEngine.LengthGeodetic(pathGeometry, LinearUnits.Kilometers, GeodeticCurveType.Geodesic);
            ResultsLabel.Text = $"{(int)distance} kilometers";
        }
    }
}