Skip to content

Project with chosen transformation

View on GitHub

Project a point from one coordinate system to another using a specific transformation step.

Image of Project with chosen transformation sample

Use case

While the geometry engine supports automatic transformation of geometry between coordinate systems, some coordinate system pairs have specific transformations defined for additional accuracy within certain areas. For example, your organization could work in a local state plane using the NAD83 or NAD83 (HARN) datums while collecting data in the standard WGS 1984 datum. Your organization can define a specific transformation step to use to ensure precise, reliable data collection.

How to use the sample

Tap a point on the map to see three values: unprojected point, projected with the GeometryEngine default, and projected with a specific transformation step.

How it works

  1. When a location is selected on the map, get its coordinates in WGS 84.
  2. Use the geometry engine to project the point without specifying a transformation step. Display the result for comparison.
  3. Use the geometry engine to project the point, this time specifying a transformation step. Display the result.
  4. Compare the results to see how a specific transformation step can result in a slightly different (and potentially more accurate) result.

Relevant API

  • GeographicTransformation
  • GeographicTransformationStep

About the data

To avoid the need to project from Mercator coordinates to WGS 84, this sample uses World Basemaps (WGS84) from ArcGIS Online's living atlas.

This sample uses the transformation identified by WKID 108055 to convert from WGS 84 to MSK 42. It is suitable for use in Mongolia and has an accuracy of 999 meters.

Additional information

See Spatial references in the ArcGIS Maps SDK for Swift guide for more information about geographic coordinate systems, geographic transformations, and projected coordinate systems.

Tags

coordinate system, geographic, project, projection, transform, transformation, transformation step

Sample Code

ProjectWithChosenTransformationView.swift
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2025 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

struct ProjectWithChosenTransformationView: View {
    /// The view model for the sample.
    @State private var model = Model()

    /// A location callout placement.
    @State private var calloutPlacement: CalloutPlacement?

    /// The point where the map was tapped in its original spatial reference (WGS84).
    @State private var originalPoint: Point!

    /// The specific projected location after normalization.
    @State private var specificProjectedPoint: Point!

    /// The non-specific projected location after normalization.
    @State private var unspecifiedProjectedPoint: Point!

    var body: some View {
        MapView(map: model.map, graphicsOverlays: [model.graphicsOverlay])
            .interactionModes([])
            .onSingleTapGesture { _, mapPoint in
                if calloutPlacement == nil {
                    // Sets the original point to where the map was tapped.
                    originalPoint = GeometryEngine.normalizeCentralMeridian(of: mapPoint) as? Point

                    // Projects to a coordinate system used in Mongolia, with WKID 28413.
                    unspecifiedProjectedPoint = GeometryEngine.project(originalPoint, into: .mongolia)

                    // Creates a geographic transformation step.
                    let transformationStep = GeographicTransformationStep(wkid: .init(108055)!)!

                    // Creates the transformation.
                    let transformation = GeographicTransformation(step: transformationStep)

                    // Projects to a coordinate system used in Mongolia, with WKID 28413 using a transformation.
                    specificProjectedPoint = GeometryEngine.project(originalPoint, into: .mongolia, datumTransformation: transformation)

                    // Updates the geometry of the point graphic.
                    model.pointGraphic.geometry = specificProjectedPoint

                    // Updates the location callout placement.
                    calloutPlacement = CalloutPlacement.location(specificProjectedPoint)
                } else {
                    // Hides the callout and point graphic.
                    calloutPlacement = nil
                    model.pointGraphic.geometry = nil
                }
            }
            .callout(placement: $calloutPlacement.animation(.default.speed(2))) { _ in
                VStack(alignment: .leading) {
                    Text("Coordinates")
                        .fontWeight(.medium)
                    Text("__Original (WGS 84):__\n\(originalPoint.xyCoordinates)")
                    Text("__Projected (non-specific):__\n\(unspecifiedProjectedPoint.xyCoordinates)")
                    Text("__Projected (WKID: 108055):__\n\(specificProjectedPoint.xyCoordinates)")
                }
                .font(.callout)
                .padding(6)
            }
            .overlay(alignment: .top) {
                Text("Tap on the map.")
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 6)
                    .background(.thinMaterial, ignoresSafeAreaEdges: .horizontal)
            }
    }
}

private extension ProjectWithChosenTransformationView {
    /// The model used to store the geo model and other expensive objects
    /// used in this view.
    final class Model {
        /// A map with a WGS84 world basemap and an initial viewpoint over Mongolia.
        let map: Map = {
            let portalItem = PortalItem(
                portal: .arcGISOnline(connection: .anonymous),
                id: .worldBasemap
            )
            let map = Map(item: portalItem)

            // The transformation used in this sample is only valid in the following area.
            let extent = Envelope(
                xRange: 87.76...119.94,
                yRange: 41.58...52.15,
                spatialReference: .wgs84
            )
            map.initialViewpoint = Viewpoint(boundingGeometry: extent)
            return map
        }()

        /// A graphics overlay for the circular, red marker symbol.
        let graphicsOverlay = GraphicsOverlay()

        /// The graphic with a circular, red marker symbol.
        let pointGraphic = Graphic(symbol: SimpleMarkerSymbol(color: .red, size: 8))

        init() {
            graphicsOverlay.addGraphic(pointGraphic)
        }
    }
}

private extension FormatStyle where Self == FloatingPointFormatStyle<Double> {
    /// Formats the double with four decimals places of precision.
    static var decimal: Self {
        number.precision(.fractionLength(4))
    }
}

private extension Point {
    /// The point's decimal-formatted x and y coordinates.
    var xyCoordinates: Text {
        Text("\(self.x, format: .decimal), \(self.y, format: .decimal)")
    }
}

private extension PortalItem.ID {
    /// The portal item ID of World Imagery Hybrid Basemap (WGS84).
    static var worldBasemap: Self { Self("4c2b44abaa4841d08c938f4bbb548561")! }
}

private extension SpatialReference {
    /// The spatial reference for the sample, a coordinate system used in Mongolia (WKID: 28413).
    static var mongolia: Self { SpatialReference(wkid: WKID(28413)!)! }
}

#Preview {
    ProjectWithChosenTransformationView()
}

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