Skip to content

Commit

Permalink
Update Nearest Vertex sample to give correct planar distance result. (#…
Browse files Browse the repository at this point in the history
…984)

* Update NearestVertex.xaml.cs

* Updated WPF NearestVertex Sample

* Updated WinUI NearestVertex Sample

* Updated Xamarin.Forms NearestVertex Sample

* Added GeometryEngine to relevant APIs

* Updated tapped cross and screenshots

* Implemented PR feedback
  • Loading branch information
duffh authored Mar 28, 2022
1 parent 5e380f3 commit 9701e52
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 95 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using System;
using Colors = System.Drawing.Color;

namespace ArcGISRuntime.Samples.NearestVertex
Expand All @@ -23,11 +24,11 @@ namespace ArcGISRuntime.Samples.NearestVertex
tags: new[] { "analysis", "coordinate", "geometry", "nearest", "proximity", "vertex" })]
public partial class NearestVertex
{
// Hold references to the graphics overlay and the polygon graphic
// Hold references to the graphics overlay and the polygon graphic.
private GraphicsOverlay _graphicsOverlay;
private Graphic _polygonGraphic;

// Hold references to the graphics for the user and results points
// Hold references to the graphics for the user and results points.
private Graphic _tappedLocationGraphic;
private Graphic _nearestVertexGraphic;
private Graphic _nearestCoordinateGraphic;
Expand All @@ -41,38 +42,50 @@ public NearestVertex()

private void Initialize()
{
// Configure the basemap
MyMapView.Map = new Map(BasemapStyle.ArcGISTopographic);
// Planar distances are only accurate for geometries that have a defined projected coordinate system.
// Create a spatial reference using the California zone 5 (ftUS) state plane coordinate system.
// This coordinate system maintains planar distance accuracy in the region of Southern California.
SpatialReference californiaZone5SpatialReference = SpatialReference.Create(2229);

// Create the graphics overlay and set the selection color
// Create a map that uses the California zone 5 state spatial reference.
MyMapView.Map = new Map(californiaZone5SpatialReference);

// Create the feature layer.
Uri uriLayerSource = new Uri("https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_States_Generalized/FeatureServer/0");
FeatureLayer usaStatesFeatureLayer = new FeatureLayer(uriLayerSource);

// Add the feature layer to the MapView.
MyMapView.Map.OperationalLayers.Add(usaStatesFeatureLayer);

// Create the graphics overlay and set the selection color.
_graphicsOverlay = new GraphicsOverlay();

// Add the overlay to the MapView
// Add the overlay to the MapView.
MyMapView.GraphicsOverlays.Add(_graphicsOverlay);

// Create the point collection that defines the polygon
PointCollection polygonPoints = new PointCollection(SpatialReferences.WebMercator)
// Create the point collection that defines the polygon.
PointCollection polygonPoints = new PointCollection(californiaZone5SpatialReference)
{
new MapPoint(-5991501.677830, 5599295.131468),
new MapPoint(-6928550.398185, 2087936.739807),
new MapPoint(-3149463.800709, 1840803.011362),
new MapPoint(-1563689.043184, 3714900.452072),
new MapPoint(-3180355.516764, 5619889.608838)
new MapPoint(6627416.41469281, 1804532.53233782),
new MapPoint(6669147.89779046, 2479145.16609522),
new MapPoint(7265673.02678292, 2484254.50442408),
new MapPoint(7676192.55880379, 2001458.66365744),
new MapPoint(7175695.94143837, 1840722.34474458)
};

// Create the polygon
// Create the polygon.
Polygon polygonGeometry = new Polygon(polygonPoints);

// Define and apply the symbology
// Define and apply the symbology.
SimpleLineSymbol polygonOutlineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Colors.Green, 2);
SimpleFillSymbol polygonFillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle.ForwardDiagonal, Colors.Green, polygonOutlineSymbol);

// Create the graphic and add it to the graphics overlay
// Create the graphic and add it to the graphics overlay.
_polygonGraphic = new Graphic(polygonGeometry, polygonFillSymbol);
_graphicsOverlay.Graphics.Add(_polygonGraphic);

// Create the graphics and symbology for the tapped point, the nearest vertex, and the nearest coordinate
SimpleMarkerSymbol tappedLocationSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, Colors.Orange, 15);
// Create the graphics and symbology for the tapped point, the nearest vertex, and the nearest coordinate.
SimpleMarkerSymbol tappedLocationSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, Colors.Black, 15);
SimpleMarkerSymbol nearestCoordinateSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Diamond, Colors.Red, 10);
SimpleMarkerSymbol nearestVertexSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Colors.Blue, 15);
_nearestCoordinateGraphic = new Graphic { Symbol = nearestCoordinateSymbol };
Expand All @@ -83,41 +96,41 @@ private void Initialize()
_graphicsOverlay.Graphics.Add(_nearestVertexGraphic);
_graphicsOverlay.Graphics.Add(_nearestCoordinateGraphic);

// Listen for taps; the spatial relationships will be updated in the handler
// Listen for taps; the spatial relationships will be updated in the handler.
MyMapView.GeoViewTapped += MapViewTapped;

// Center the map on the polygon
MyMapView.SetViewpointCenterAsync(polygonGeometry.Extent.GetCenter(), 200000000);
MyMapView.SetViewpointCenterAsync(polygonGeometry.Extent.GetCenter(), 8000000);
}

private void MapViewTapped(object sender, Esri.ArcGISRuntime.Xamarin.Forms.GeoViewInputEventArgs geoViewInputEventArgs)
{
// Get the tapped location
// Get the tapped location.
MapPoint tappedLocation = (MapPoint)GeometryEngine.NormalizeCentralMeridian(geoViewInputEventArgs.Location);

// Show the tapped location
// Show the tapped location.
_tappedLocationGraphic.Geometry = tappedLocation;

// Get the nearest vertex in the polygon
ProximityResult nearestVertexResult = GeometryEngine.NearestVertex(_polygonGraphic.Geometry, tappedLocation);

// Get the nearest coordinate in the polygon
// Get the nearest coordinate in the polygon.
ProximityResult nearestCoordinateResult =
GeometryEngine.NearestCoordinate(_polygonGraphic.Geometry, tappedLocation);

// Get the distance to the nearest vertex in the polygon
// Get the distance to the nearest vertex in the polygon.
int distanceVertex = (int)(nearestVertexResult.Distance / 1000);

// Get the distance to the nearest coordinate in the polygon
// Get the distance to the nearest coordinate in the polygon.
int distanceCoordinate = (int)(nearestCoordinateResult.Distance / 1000);

// Show the nearest vertex in blue
// Show the nearest vertex in blue.
_nearestVertexGraphic.Geometry = nearestVertexResult.Coordinate;

// Show the nearest coordinate in red
// Show the nearest coordinate in red.
_nearestCoordinateGraphic.Geometry = nearestCoordinateResult.Coordinate;

// Show the distances in the UI
// Show the distances in the UI.
ResultsLabel.Text = $"Vertex dist: {distanceVertex} km, Point dist: {distanceCoordinate} km";
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/Forms/Shared/Samples/Geometry/NearestVertex/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,25 @@ Determine the shortest distance between a location and the boundary of an area.

## How to use the sample

Tap anywhere on the map. An orange cross will show at that location. A blue circle will show the polygon's nearest vertex to the point that was clicked. A red diamond will appear at the coordinate on the geometry that is nearest to the point that was clicked. If clicked inside the geometry, the red and orange markers will overlap. The information box showing distance between the clicked point and the nearest vertex/coordinate will be updated with every new location clicked.
Tap anywhere on the map. An orange cross will show at that location. A blue circle will show the polygon's nearest vertex to the point that was tapped. A red diamond will appear at the coordinate on the geometry that is nearest to the point that was tapped. If tapped inside the geometry, the red and orange markers will overlap. The information box showing distance between the tapped point and the nearest vertex/coordinate will be updated with every new location tapped.

## How it works

1. Get a `Geometry` and a `Point` to check the nearest vertex against.
2. Call `GeometryEngine.NearestVertex(inputGeometry, point)`.
3. Use the returned `ProximityResult` to get the `Point` representing the polygon vertex, and to determine the distance between that vertex and the clicked point.
3. Use the returned `ProximityResult` to get the `Point` representing the polygon vertex, and to determine the distance between that vertex and the tapped point.
4. Call `GeometryEngine.NearestCoordinate(inputGeometry, point)`.
5. Use the returned `ProximityResult` to get the `Point` representing the coordinate on the polygon, and to determine the distance between that coordinate and the clicked point.
5. Use the returned `ProximityResult` to get the `Point` representing the coordinate on the polygon, and to determine the distance between that coordinate and the tapped point.

## Relevant API

* GeometryEngine
* ProximityResult

## Additional information

The value of `ProximityResult.distance` is planar (Euclidean) distance. Planar distances are only accurate for geometries that have a defined projected coordinate system, which maintain the desired level of accuracy. The example polygon in this sample is defined in California State Plane Coordinate System - Zone 5 (WKID 2229), which maintains accuracy near Southern California. Accuracy declines outside the state plane zone.

## Tags

analysis, coordinate, geometry, nearest, proximity, vertex
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.UI.Controls;
using System;
using System.Threading.Tasks;

namespace ArcGISRuntime.WPF.Samples.NearestVertex
{
Expand All @@ -23,11 +25,11 @@ namespace ArcGISRuntime.WPF.Samples.NearestVertex
tags: new[] { "analysis", "coordinate", "geometry", "nearest", "proximity", "vertex" })]
public partial class NearestVertex
{
// Hold references to the graphics overlay and the polygon graphic
// Hold references to the graphics overlay and the polygon graphic.
private GraphicsOverlay _graphicsOverlay;
private Graphic _polygonGraphic;

// Hold references to the graphics for the user and results points
// Hold references to the graphics for the user and results points.
private Graphic _tappedLocationGraphic;
private Graphic _nearestVertexGraphic;
private Graphic _nearestCoordinateGraphic;
Expand All @@ -37,43 +39,55 @@ public NearestVertex()
InitializeComponent();

// Create the map, set the initial extent, and add the original point graphic.
Initialize();
_ = Initialize();
}

private void Initialize()
private async Task Initialize()
{
// Configure the basemap
MyMapView.Map = new Map(BasemapStyle.ArcGISTopographic);
// Planar distances are only accurate for geometries that have a defined projected coordinate system.
// Create a spatial reference using the California zone 5 (ftUS) state plane coordinate system.
// This coordinate system maintains planar distance accuracy in the region of Southern California.
SpatialReference californiaZone5SpatialReference = SpatialReference.Create(2229);

// Create the graphics overlay and set the selection color
// Create a map that uses the California zone 5 state spatial reference.
MyMapView.Map = new Map(californiaZone5SpatialReference);

// Create the feature layer.
Uri uriLayerSource = new Uri("https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_States_Generalized/FeatureServer/0");
FeatureLayer usaStatesFeatureLayer = new FeatureLayer(uriLayerSource);

// Add the feature layer to the MapView.
MyMapView.Map.OperationalLayers.Add(usaStatesFeatureLayer);

// Create the graphics overlay and set the selection color.
_graphicsOverlay = new GraphicsOverlay();

// Add the overlay to the MapView
// Add the overlay to the MapView.
MyMapView.GraphicsOverlays.Add(_graphicsOverlay);

// Create the point collection that defines the polygon
PointCollection polygonPoints = new PointCollection(SpatialReferences.WebMercator)
// Create the point collection that defines the polygon.
PointCollection polygonPoints = new PointCollection(californiaZone5SpatialReference)
{
new MapPoint(-5991501.677830, 5599295.131468),
new MapPoint(-6928550.398185, 2087936.739807),
new MapPoint(-3149463.800709, 1840803.011362),
new MapPoint(-1563689.043184, 3714900.452072),
new MapPoint(-3180355.516764, 5619889.608838)
new MapPoint(6627416.41469281, 1804532.53233782),
new MapPoint(6669147.89779046, 2479145.16609522),
new MapPoint(7265673.02678292, 2484254.50442408),
new MapPoint(7676192.55880379, 2001458.66365744),
new MapPoint(7175695.94143837, 1840722.34474458)
};

// Create the polygon
// Create the polygon.
Polygon polygonGeometry = new Polygon(polygonPoints);

// Define and apply the symbology
// Define and apply the symbology.
SimpleLineSymbol polygonOutlineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, System.Drawing.Color.Green, 2);
SimpleFillSymbol polygonFillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle.ForwardDiagonal, System.Drawing.Color.Green, polygonOutlineSymbol);

// Create the graphic and add it to the graphics overlay
// Create the graphic and add it to the graphics overlay.
_polygonGraphic = new Graphic(polygonGeometry, polygonFillSymbol);
_graphicsOverlay.Graphics.Add(_polygonGraphic);

// Create the graphics and symbology for the tapped point, the nearest vertex, and the nearest coordinate
SimpleMarkerSymbol tappedLocationSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, System.Drawing.Color.Orange, 15);
// Create the graphics and symbology for the tapped point, the nearest vertex, and the nearest coordinate.
SimpleMarkerSymbol tappedLocationSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.X, System.Drawing.Color.Black, 15);
SimpleMarkerSymbol nearestCoordinateSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Diamond, System.Drawing.Color.Red, 10);
SimpleMarkerSymbol nearestVertexSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, System.Drawing.Color.Blue, 15);
_nearestCoordinateGraphic = new Graphic { Symbol = nearestCoordinateSymbol };
Expand All @@ -84,43 +98,43 @@ private void Initialize()
_graphicsOverlay.Graphics.Add(_nearestVertexGraphic);
_graphicsOverlay.Graphics.Add(_nearestCoordinateGraphic);

// Listen for taps; the spatial relationships will be updated in the handler
// Listen for taps; the spatial relationships will be updated in the handler.
MyMapView.GeoViewTapped += MapViewTapped;

// Center the map on the polygon
MyMapView.SetViewpointCenterAsync(polygonGeometry.Extent.GetCenter(), 200000000);
// Center the map on the polygon.
await MyMapView.SetViewpointCenterAsync(polygonGeometry.Extent.GetCenter(), 8000000);
}

private void MapViewTapped(object sender, GeoViewInputEventArgs geoViewInputEventArgs)
{
// Get the tapped location
// Get the tapped location.
MapPoint tappedLocation = (MapPoint)GeometryEngine.NormalizeCentralMeridian(geoViewInputEventArgs.Location);

// Show the tapped location
// Show the tapped location.
_tappedLocationGraphic.Geometry = tappedLocation;

// Get the nearest vertex in the polygon
// Get the nearest vertex in the polygon.
ProximityResult nearestVertexResult = GeometryEngine.NearestVertex(_polygonGraphic.Geometry, tappedLocation);

// Get the nearest coordinate in the polygon
// Get the nearest coordinate in the polygon.
ProximityResult nearestCoordinateResult =
GeometryEngine.NearestCoordinate(_polygonGraphic.Geometry, tappedLocation);

// Get the distance to the nearest vertex in the polygon
// Get the distance to the nearest vertex in the polygon.
int distanceVertex = (int)(nearestVertexResult.Distance / 1000);

// Get the distance to the nearest coordinate in the polygon
// Get the distance to the nearest coordinate in the polygon.
int distanceCoordinate = (int)(nearestCoordinateResult.Distance / 1000);

// Show the nearest vertex in blue
// Show the nearest vertex in blue.
_nearestVertexGraphic.Geometry = nearestVertexResult.Coordinate;

// Show the nearest coordinate in red
// Show the nearest coordinate in red.
_nearestCoordinateGraphic.Geometry = nearestCoordinateResult.Coordinate;

// Show the distances in the UI
// Show the distances in the UI.
ResultsLabel.Content =
string.Format("Vertex dist: {0} km, Point dist: {1} km", distanceVertex, distanceCoordinate);
string.Format("Vertex distance: {0} km, Point dist: {1} km", distanceVertex, distanceCoordinate);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Click anywhere on the map. An orange cross will show at that location. A blue ci
* GeometryEngine
* ProximityResult

## Additional information

The value of `ProximityResult.distance` is planar (Euclidean) distance. Planar distances are only accurate for geometries that have a defined projected coordinate system, which maintain the desired level of accuracy. The example polygon in this sample is defined in California State Plane Coordinate System - Zone 5 (WKID 2229), which maintains accuracy near Southern California. Accuracy declines outside the state plane zone.

## Tags

analysis, coordinate, geometry, nearest, proximity, vertex
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9701e52

Please sign in to comment.