Geodesic operations

View inC++QMLView on GitHubSample viewer app

Calculate a geodesic path between two points and measure its distance.

screenshot

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

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. Click elsewhere and a new line will be created.

How it works

  1. Create a Point in New York City and display it as a Graphic.
  2. Obtain a new point when a click occurs on the MapView and add this point as a graphic.
  3. Create a Polyline from the two points.
  4. Execute GeometryEngine::densifyGeodetic by passing in the created polyine then create a graphic from the returned Geometry.
  5. Execute GeometryEngine::lengthGeodetic by passing in the two points and display the returned length 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

GeodesicOperations.cppGeodesicOperations.cppGeodesicOperations.hGeodesicOperations.qml
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// [WriteFile Name=GeodesicOperations, Category=Geometry]
// [Legal]
// 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.
// [Legal]

#ifdef PCH_BUILD
#include "pch.hpp"
#endif // PCH_BUILD

#include "GeodesicOperations.h"

#include "Map.h"
#include "MapQuickView.h"
#include "GraphicsOverlay.h"
#include "Graphic.h"
#include "SimpleMarkerSymbol.h"
#include "SimpleLineSymbol.h"
#include "GeometryEngine.h"
#include "SpatialReference.h"
#include "PolylineBuilder.h"
#include "Point.h"
#include "MapTypes.h"
#include "GraphicsOverlayListModel.h"
#include "GraphicListModel.h"
#include "SymbolTypes.h"
#include "LinearUnit.h"

using namespace Esri::ArcGISRuntime;

GeodesicOperations::GeodesicOperations(QQuickItem* parent /* = nullptr */):
  QQuickItem(parent)
{
}

void GeodesicOperations::init()
{
  // Register the map view for QML
  qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
  qmlRegisterType<GeodesicOperations>("Esri.Samples", 1, 0, "GeodesicOperationsSample");
}

void GeodesicOperations::componentComplete()
{
  QQuickItem::componentComplete();

  // find QML MapView component
  m_mapView = findChild<MapQuickView*>("mapView");

  // Create a map using the imagery basemap
  m_map = new Map(BasemapStyle::ArcGISImageryStandard, this);

  // Set map to map view
  m_mapView->setMap(m_map);

  // Create a GraphicsOverlay
  GraphicsOverlay* graphicsOverlay = new GraphicsOverlay(this);
  m_mapView->graphicsOverlays()->append(graphicsOverlay);

  // Create Graphic Symbols
  SimpleMarkerSymbol* markerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle::Circle, QColor("blue"), 10.0f /*size*/, this);
  SimpleLineSymbol* pathSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Dash, QColor("blue"), 5.0f /*width*/, this);

  // Create NYC graphic
  const Point nycPoint(-73.7781, 40.6413, SpatialReference(4326));
  m_nycGraphic = new Graphic(nycPoint, markerSymbol, this);
  graphicsOverlay->graphics()->append(m_nycGraphic);

  // Create destination graphic
  m_destinationGraphic = new Graphic(this);
  m_destinationGraphic->setSymbol(markerSymbol);
  graphicsOverlay->graphics()->append(m_destinationGraphic);

  // Create path graphic
  m_pathGraphic = new Graphic(this);
  m_pathGraphic->setSymbol(pathSymbol);
  graphicsOverlay->graphics()->append(m_pathGraphic);

  // connect to mouse clicked signal
  connect(m_mapView, &MapQuickView::mouseClicked, this, [this, nycPoint](QMouseEvent& mouseEvent)
  {
    // re-project the point to match the NYC graphic
    const Point clickedPoint = m_mapView->screenToLocation(mouseEvent.position().x(), mouseEvent.position().y());
    const Point destination = geometry_cast<Point>(GeometryEngine::project(clickedPoint, m_nycGraphic->geometry().spatialReference()));

    // update the destination graphic
    m_destinationGraphic->setGeometry(destination);

    // create line with start/end points
    const QList<Point> points = {nycPoint, destination};
    const Polyline polyline = pointsToPolyline(points);

    // densify the path as a geodesic curve and show it with the path graphic
    constexpr double maxSegmentLength = 1.0;
    const LinearUnit unitOfMeasurement(LinearUnitId::Kilometers);
    constexpr GeodeticCurveType curveType = GeodeticCurveType::Geodesic;
    const Geometry pathGeometry = GeometryEngine::densifyGeodetic(polyline, maxSegmentLength, unitOfMeasurement, curveType);

    // update the graphic
    m_pathGraphic->setGeometry(pathGeometry);

    // calculate the path's geodetic length
    m_distanceText = QString::number(GeometryEngine::lengthGeodetic(pathGeometry, unitOfMeasurement, curveType), 'f', 2);
    emit distanceTextChanged();
  });
}

// helper function to create a new Polyline from a list of points
Polyline GeodesicOperations::pointsToPolyline(const QList<Point>& points)
{
  PolylineBuilder polylineBuilder(SpatialReference(4326));
  for (const Point& point : points)
    polylineBuilder.addPoint(point);

  return polylineBuilder.toPolyline();
}

QString GeodesicOperations::distanceText() const
{
  return m_distanceText;
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.