Format coordinates in a variety of common notations.
      
   
    
Use case
The coordinate formatter can format a map location in WGS84 in a number of common coordinate notations. Parsing one of these formats to a location is also supported. Formats include decimal degrees; degrees, minutes, seconds; Universal Transverse Mercator (UTM), and United States National Grid (USNG).
How to use the sample
Tap on the map to see a marker with the tapped location's coordinate formatted in 4 different ways. You can also put a coordinate string in any of these formats in the text field. Hit Enter and the coordinate string will be parsed to a map location which the marker will move to.
How it works
- Get or create a map Pointwith a spatial reference.
- Use one of the static "to" methods on CoordinateFormattersuch asCoordinateFormatter.toLatitudeLongitudeOrNull(point = newLocation, format = LatitudeLongitudeFormat.DecimalDegrees, decimalPlaces = 4)to get the formatted string.
- To go from a formatted string to a Point, use one of the "from" static methods likeCoordinateFormatter.fromUtmOrNull(coordinates = coordinateNotation, utmConversionMode = UtmConversionMode.LatitudeBandIndicators, spatialReference = null).
Relevant API
- CoordinateFormatter
- CoordinateFormatter.LatitudeLongitudeFormat
- CoordinateFormatter.UtmConversionMode
Additional information
This sample uses the GeoView-Compose Toolkit module to be able to implement a composable MapView.
Tags
convert, coordinate, decimal degrees, degree minutes seconds, format, geoview-compose, latitude, longitude, toolkit, USNG, UTM
Sample Code
/* Copyright 2023 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.
 *
 */
package com.esri.arcgismaps.sample.showcoordinatesinmultipleformats.components
import android.app.Application
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import com.arcgismaps.Color
import com.arcgismaps.geometry.CoordinateFormatter
import com.arcgismaps.geometry.LatitudeLongitudeFormat
import com.arcgismaps.geometry.Point
import com.arcgismaps.geometry.SpatialReference
import com.arcgismaps.geometry.UtmConversionMode
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbol
import com.arcgismaps.mapping.symbology.SimpleMarkerSymbolStyle
import com.arcgismaps.mapping.view.Graphic
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel
class MapViewModel(application: Application) : AndroidViewModel(application) {
    var decimalDegrees by mutableStateOf("")
        private set
    var degreesMinutesSeconds by mutableStateOf("")
        private set
    var utm by mutableStateOf("")
        private set
    var usng by mutableStateOf("")
        private set
    // create a ViewModel to handle dialog interactions
    val messageDialogVM: MessageDialogViewModel = MessageDialogViewModel()
    // set up a graphic to indicate where the coordinates relate to, with an initial location
    val initialPoint = Point(0.0, 0.0, SpatialReference.wgs84())
    val coordinateLocationGraphic = Graphic(
        geometry = initialPoint,
        symbol = SimpleMarkerSymbol(
            style = SimpleMarkerSymbolStyle.Cross,
            color = Color.fromRgba(255, 255, 0, 255),
            size = 20f
        )
    )
    /**
     * Uses CoordinateFormatter to update the UI with coordinate notation strings based on the
     * given [newLocation] point to convert to coordinate notations
     */
    fun toCoordinateNotationFromPoint(newLocation: Point) {
        coordinateLocationGraphic.geometry = newLocation
        // use CoordinateFormatter to convert to Latitude Longitude, formatted as Decimal Degrees
        decimalDegrees = CoordinateFormatter.toLatitudeLongitudeOrNull(
            point = newLocation,
            format = LatitudeLongitudeFormat.DecimalDegrees,
            decimalPlaces = 4
        ) ?: return messageDialogVM.showMessageDialog("Failed to convert from point DD coordinate")
        // use CoordinateFormatter to convert to Latitude Longitude, formatted as Degrees, Minutes, Seconds
        degreesMinutesSeconds = CoordinateFormatter.toLatitudeLongitudeOrNull(
            point = newLocation,
            format = LatitudeLongitudeFormat.DegreesMinutesSeconds,
            decimalPlaces = 4
        ) ?: return messageDialogVM.showMessageDialog("Failed to convert from point DMS coordinate")
        // use CoordinateFormatter to convert to Universal Transverse Mercator, using latitudinal bands indicator
        utm = CoordinateFormatter.toUtmOrNull(
            point = newLocation,
            utmConversionMode = UtmConversionMode.LatitudeBandIndicators,
            addSpaces = true
        ) ?: return messageDialogVM.showMessageDialog("Failed to convert from point UTM coordinate")
        // use CoordinateFormatter to convert to United States National Grid (USNG)
        usng = CoordinateFormatter.toUsngOrNull(
            point = newLocation,
            precision = 4,
            addSpaces = true,
        ) ?: return messageDialogVM.showMessageDialog("Failed to convert from point USNG coordinate")
    }
    /**
     * Uses CoordinateFormatter to update the graphic in the map from the given [coordinateNotation]
     * string entered by the user. Also calls corresponding method to update all the remaining
     * [coordinateNotation] strings using the notation [notationType].
     */
    fun fromCoordinateNotationToPoint(notationType: NotationType, coordinateNotation: String) {
        // ignore empty input coordinate notation strings, do not update UI
        if (coordinateNotation.isEmpty()) return
        val convertedPoint: Point = when (notationType) {
            NotationType.DMS, NotationType.DD -> {
                // use CoordinateFormatter to parse Latitude Longitude - different numeric notations (Decimal Degrees;
                // Degrees, Minutes, Seconds; Degrees, Decimal Minutes) can all be passed to this same method
                CoordinateFormatter.fromLatitudeLongitudeOrNull(
                    coordinates = coordinateNotation,
                    spatialReference = null
                ) ?: return messageDialogVM.showMessageDialog("Failed to convert DMS/DD coordinate to point")
            }
            NotationType.UTM -> {
                // use CoordinateFormatter to parse UTM coordinates
                CoordinateFormatter.fromUtmOrNull(
                    coordinates = coordinateNotation,
                    utmConversionMode = UtmConversionMode.LatitudeBandIndicators,
                    spatialReference = null
                ) ?: return messageDialogVM.showMessageDialog("Failed to convert UTM coordinate to point")
            }
            NotationType.USNG -> {
                // use CoordinateFormatter to parse US National Grid coordinates
                CoordinateFormatter.fromUsngOrNull(
                    coordinates = coordinateNotation,
                    spatialReference = null
                ) ?: return messageDialogVM.showMessageDialog("Failed to convert USNG coordinate to point")
            }
        }
        // update the location shown in the map
        toCoordinateNotationFromPoint(convertedPoint)
    }
    /**
     * Coordinate notations supported by this sample
     */
    enum class NotationType {
        DMS, DD, UTM, USNG
    }
    /**
     * Set's [decimalDegrees] entered in the text field to the [inputString]
     */
    fun setDecimalDegreesCoordinate(inputString: String) {
        decimalDegrees = inputString
    }
    /**
     * Set's [degreesMinutesSeconds] entered in the text field to the [inputString]
     */
    fun degreesMinutesSecondsCoordinate(inputString: String) {
        degreesMinutesSeconds = inputString
    }
    /**
     * Set's [utm] entered in the text field to the [inputString]
     */
    fun setUTMCoordinate(inputString: String) {
        utm = inputString
    }
    /**
     * Set's [usng] entered in the text field to the [inputString]
     */
    fun setUSNGDegreesCoordinate(inputString: String) {
        usng = inputString
    }
}