Calculate a geodesic path between two points and measure its distance.
Use case
A geodesic distance provides an accurate, real-world distance between two points. Visualizing flight paths between cities is a common example of a geodesic operation since the flight path between two airports takes into account the curvature of the earth, rather than following the planar path between those points, which appears as a straight line on a projected map.
How to use the sample
Tap 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. Tap elsewhere and a new line will be created.
How it works
- A
Point
is created in New York City and displayed as aGraphic
. - When a tap occurs on the
MapView
, a newPoint
is obtained from the mouse click. ThisPoint
is added as aGraphic
. - A
Polyline
is created with the twoPoint
objects. GeometryEngine.DensifyGeodetic
is executed by passing in thePolyline
object, and the returnedGeometry
is added as aGraphic
.GeometryEngine.LengthGeodetic
is executed by passing in the twoPoint
objects, and the returned number is displayed on the screen.
Relevant API
- GeometryEngine.DensifyGeodetic
- GeometryEngine.LengthGeodetic
About the data
The Imagery basemap provides the global context for the displayed geodesic line.
Tags
densify, distance, geodesic, geodetic
Sample Code
// 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;
using Foundation;
using UIKit;
namespace ArcGISRuntime.Samples.GeodesicOperations
{
[Register("GeodesicOperations")]
[ArcGISRuntime.Samples.Shared.Attributes.Sample(
name: "Geodesic operations",
category: "Geometry",
description: "Calculate a geodesic path between two points and measure its distance.",
instructions: "Tap 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. Tap elsewhere and a new line will be created.",
tags: new[] { "densify", "distance", "geodesic", "geodetic" })]
public class GeodesicOperations : UIViewController
{
// Hold references to UI controls.
private MapView _myMapView;
private UILabel _distanceLabel;
// Hold references to the graphics.
private Graphic _startLocationGraphic;
private Graphic _endLocationGraphic;
private Graphic _pathGraphic;
public GeodesicOperations()
{
Title = "Geodesic operations";
}
private void Initialize()
{
// Create and show a new map with imagery basemap.
_myMapView.Map = new Map(BasemapStyle.ArcGISImageryStandard);
// 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);
}
private void MyMapView_GeoViewTapped(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);
_distanceLabel.Text = $"{(int) distance} kilometers";
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Initialize();
}
public override void LoadView()
{
// Create the views.
View = new UIView() { BackgroundColor = ApplicationTheme.BackgroundColor };
_myMapView = new MapView();
_myMapView.TranslatesAutoresizingMaskIntoConstraints = false;
_distanceLabel = new UILabel
{
Text = "Tap to set an end point.",
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.FromWhiteAlpha(0, .8f),
TextColor = UIColor.White,
TranslatesAutoresizingMaskIntoConstraints = false
};
// Add the views.
View.AddSubviews(_myMapView, _distanceLabel);
// Lay out the views.
NSLayoutConstraint.ActivateConstraints(new[]
{
_myMapView.TopAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.TopAnchor),
_myMapView.LeadingAnchor.ConstraintEqualTo(View.LeadingAnchor),
_myMapView.TrailingAnchor.ConstraintEqualTo(View.TrailingAnchor),
_myMapView.BottomAnchor.ConstraintEqualTo(View.BottomAnchor),
_distanceLabel.TopAnchor.ConstraintEqualTo(View.SafeAreaLayoutGuide.TopAnchor),
_distanceLabel.LeadingAnchor.ConstraintEqualTo(View.LeadingAnchor),
_distanceLabel.TrailingAnchor.ConstraintEqualTo(View.TrailingAnchor),
_distanceLabel.HeightAnchor.ConstraintEqualTo(40)
});
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
// Subscribe to events.
_myMapView.GeoViewTapped += MyMapView_GeoViewTapped;
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
// Unsubscribe from events, per best practice.
_myMapView.GeoViewTapped -= MyMapView_GeoViewTapped;
}
}
}