Being able to project between spatial references is fundamental in GIS. An example of when you would need to re-project data is if you had data in two different spatial references, but wanted to perform an intersect analysis with the static GeometryEngine.intersection(_:_:) method. This method takes two geometries as parameters, and both geometries must be in the same spatial reference. If they are not, you could first use static GeometryEngine.project(_:into:) to convert the geometries so they match.
How to use the sample
Tap anywhere on the map. A callout will display the tapped location's coordinate in the original basemap's spatial reference webMercator and in the projected spatial reference wgs84.
How it works
Call the method, static GeometryEngine.project(_:into:), passing in the original geometry and a spatial reference system to be projected to.
Relevant API
GeometryEngine
Point
SpatialReference
static GeometryEngine.project(_:into:)
Additional information
In cases where the output spatial reference uses a different geographic coordinate system than that of the input spatial reference, see the static GeometryEngine.project(_:into:datumTransformation:) method that additionally takes in a DatumTransformation parameter.
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
// Copyright 2022 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//// https://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.import ArcGIS
import SwiftUI
structProjectGeometryView: View{
/// A location callout placement.@Stateprivatevar calloutPlacement: LocationCalloutPlacement?
/// The point where the map was tapped in its original spatial reference (Web Mercator).@Stateprivatevar originalPoint: Point?
/// A map with a topographic basemap style and an initial viewpoint.@StateObjectprivatevar map: Map= {
let map =Map(basemapStyle: .arcGISTopographic)
map.initialViewpoint =Viewpoint(
center: Point(x: -1.2e7, y: 5e6, spatialReference: .webMercator),
scale: 4e7 )
return map
}()
/// A graphics overlay containing a graphic with a circular, red marker symbol.@StateObjectprivatevar graphicsOverlay =GraphicsOverlay(graphics: [
Graphic(symbol: SimpleMarkerSymbol(color: .red, size: 8))
])
/// The graphic with a circular, red marker symbol.privatevar pointGraphic: Graphic { graphicsOverlay.graphics.first! }
var body: someView {
MapView(map: map, graphicsOverlays: [graphicsOverlay])
.onSingleTapGesture { _, mapPoint inif calloutPlacement ==nil {
// Sets the original point to where the map was tapped. originalPoint =GeometryEngine.normalizeCentralMeridian(of: mapPoint) as?Point// Projects the original point from Web Mercator to WGS 84.let projectedPoint =GeometryEngine.project(originalPoint!, into: .wgs84)!// Updates the geometry of the point graphic. pointGraphic.geometry = projectedPoint
// Updates the location callout placement. calloutPlacement =LocationCalloutPlacement(location: projectedPoint)
} else {
// Hides the callout and point graphic. calloutPlacement =nil pointGraphic.geometry =nil }
}
.callout(placement: $calloutPlacement.animation(.default.speed(4))) { callout inVStack(alignment: .leading) {
Group {
Text("Coordinates")
.fontWeight(.medium)
Text("Original: \(originalPoint!.xyCoordinates)")
Text("Projected: \(callout.location.xyCoordinates)")
}
.font(.callout)
}
.padding(6)
}
.overlay(alignment: .top) {
Text("Tap on the map.")
.frame(maxWidth: .infinity)
.padding(.vertical, 6)
.background(.thinMaterial, ignoresSafeAreaEdges: .horizontal)
}
}
}
privateextensionFormatStylewhereSelf == FloatingPointFormatStyle<Double> {
/// Formats the double with four decimals places of precision.staticvar decimal: Self {
Self.number.precision(.fractionLength(4))
}
}
privateextensionPoint{
/// The point's decimal-formatted x and y coordinates.var xyCoordinates: Text {
Text("\(self.x, format: .decimal), \(self.y, format: .decimal)")
}
}