Display and customize coordinate system grids including Latitude/Longitude, MGRS, UTM and USNG on a map view or scene view.
Use case
Grids are often used on printed maps, but can also be helpful on digital 2D maps or 3D scenes, to identify locations.
How to use the sample
Tap on the Change Grid
button in the toolbar to open a settings view. You can change the view from 2D or 3D, select the type of grid from Grid Type
(LatLong, MGRS, UTM, and USNG) and modify its properties like label visibility, grid line color, grid label color, and label formatting.
How it works
- Create an instance of one of the
Grid
types. - Grid lines and labels can be styled per grid level with
setLineSymbol(gridLevel, lineSymbol)
andsetTextSymbol(gridLevel, textSymbol)
methods on the grid. - The label position can be set with
setLabelPosition(labelPosition)
method on the grid.- Note that as of 200.6, MGRS, UTM, and USNG grids in a SceneView only support the
Geographic
label position.
- Note that as of 200.6, MGRS, UTM, and USNG grids in a SceneView only support the
- For the
LatitudeLongitudeGrid
type, you can specify a label format ofDECIMAL_DEGREES
orDEGREES_MINUTES_SECONDS
. - To set the grid, use the
setGrid(grid)
method on the map view or scene view.
Relevant API
- ArcGISGrid
- LatitudeLongitudeGrid
- LatitudeLongitudeGridLabelFormat::DecimalDegrees
- LatitudeLongitudeGridLabelFormat::DegreesMinutesSeconds
- MapView
- MGRSGrid
- SceneView
- SimpleLineSymbol
- TextSymbol
- USNGGrid
- UTMGrid
Tags
coordinates, degrees, graticule, grid, latitude, longitude, MGRS, minutes, seconds, USNG, UTM
Sample Code
// [WriteFile Name=ShowGrid, Category=DisplayInformation]
// [Legal]
// Copyright 2024 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 "ShowGrid.h"
#include "ArcGISTiledElevationSource.h"
#include "ElevationSourceListModel.h"
#include "LatitudeLongitudeGrid.h"
#include "Map.h"
#include "MapTypes.h"
#include "MapQuickView.h"
#include "MapViewTypes.h"
#include "MGRSGrid.h"
#include "Point.h"
#include "Scene.h"
#include "SceneQuickView.h"
#include "SimpleLineSymbol.h"
#include "SpatialReference.h"
#include "Surface.h"
#include "TextSymbol.h"
#include "USNGGrid.h"
#include "UTMGrid.h"
#include "Viewpoint.h"
#include <QFuture>
using namespace Esri::ArcGISRuntime;
ShowGrid::ShowGrid(QObject* parent /* = nullptr */):
QObject(parent),
m_map(new Map(BasemapStyle::ArcGISImagery, this)),
m_scene(new Scene(BasemapStyle::ArcGISImagery, this))
{
// create a new elevation source from Terrain3D REST service
ArcGISTiledElevationSource* elevationSource = new ArcGISTiledElevationSource(
QUrl("https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer"), this);
// add the elevation source to the scene to display elevation
m_scene->baseSurface()->elevationSources()->append(elevationSource);
// Set the sample's initial GeoView type to MapView
m_currentViewType = s_mapView;
// Set the initial viewpoint of the map
constexpr double targetScale = 6450785;
m_map->setInitialViewpoint(Viewpoint(Point(-10336141.70018318, 5418213.05332071, SpatialReference::webMercator()), targetScale));
// Set the intial grid to LatitudeLongitudeGrid
m_grid = new LatitudeLongitudeGrid(this);
}
ShowGrid::~ShowGrid() = default;
void ShowGrid::init()
{
// Register classes for QML
qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
qmlRegisterType<SceneQuickView>("Esri.Samples", 1, 0, "SceneView");
qmlRegisterType<ShowGrid>("Esri.Samples", 1, 0, "ShowGridSample");
}
MapQuickView* ShowGrid::mapView() const
{
return m_mapView;
}
// Set the view (created in QML)
void ShowGrid::setMapView(MapQuickView* mapView)
{
if (!mapView || mapView == m_mapView)
return;
m_mapView = mapView;
m_mapView->setMap(m_map);
m_mapView->setGrid(m_grid);
emit mapViewChanged();
}
SceneQuickView* ShowGrid::sceneView() const
{
return m_sceneView;
}
// Set the view (created in QML)
void ShowGrid::setSceneView(SceneQuickView* sceneView)
{
if (!sceneView || sceneView == m_sceneView)
return;
m_sceneView = sceneView;
m_sceneView->setArcGISScene(m_scene);
// Set the SceneView initially to be invisible
m_sceneView->setVisible(false);
emit sceneViewChanged();
}
void ShowGrid::setViewType(const QString& viewType)
{
if (m_currentViewType == viewType)
return;
m_currentViewType = viewType;
// MapView and SceneView share the same inherited class GeoView
GeoView* newGeoView = viewType == s_mapView ? dynamic_cast<GeoView*>(m_mapView) : dynamic_cast<GeoView*>(m_sceneView);
GeoView* oldGeoView = viewType != s_mapView ? dynamic_cast<GeoView*>(m_mapView) : dynamic_cast<GeoView*>(m_sceneView);
// Set the viewpoint of the new view to the current viewpoint of the old view
newGeoView->setViewpointAsync(oldGeoView->currentViewpoint(ViewpointType::BoundingGeometry), 0);
// The Grid cannot be shared between a MapView and a SceneView so we need to unset it first
oldGeoView->setGrid(nullptr);
newGeoView->setGrid(m_grid);
emit viewTypeChanged();
}
void ShowGrid::setGridType(const QString& gridType)
{
if (m_currentGridType == gridType)
return;
m_currentGridType = gridType;
if (m_grid)
{
delete m_grid;
m_grid = nullptr;
}
// Create a new Grid of the selected type
if (gridType == s_latLong)
m_grid = new LatitudeLongitudeGrid(this);
else if (gridType == s_mgrs)
m_grid = new MGRSGrid(this);
else if (gridType == s_utm)
m_grid = new UTMGrid(this);
else if (gridType == s_usng)
m_grid = new USNGGrid(this);
// Set the grid on the current view
if (m_currentViewType == s_mapView)
m_mapView->setGrid(m_grid);
else
m_sceneView->setGrid(m_grid);
// Set properties from current UI values
setGridVisible(m_gridVisible);
setLabelsVisible(m_labelsVisible);
setLineColor(m_currentLineColor);
setLabelColor(m_currentLabelColor);
setLabelPosition(m_currentLabelPosition);
setLabelFormat(m_currentLabelFormat);
emit gridTypeChanged();
}
void ShowGrid::setGridVisible(bool visible)
{
if (m_grid->isVisible() == visible)
return;
m_gridVisible = visible;
m_grid->setVisible(visible);
emit gridVisibleChanged();
}
void ShowGrid::setLabelsVisible(bool visible)
{
if (m_grid->isLabelsVisible() == visible)
return;
m_labelsVisible = visible;
m_grid->setLabelsVisible(visible);
emit labelsVisibleChanged();
}
void ShowGrid::setLineColor(const QString& lineColor)
{
m_currentLineColor = lineColor;
SimpleLineSymbol* lineSymbol = static_cast<SimpleLineSymbol*>(m_grid->lineSymbol(0));
lineSymbol->setColor(lineColor.toLower());
// Some grids have multiple levels, in this sample we set the same symbol for all levels
for (int level = 0; level < m_grid->levelCount(); ++level)
m_grid->setLineSymbol(level, lineSymbol);
emit lineColorChanged();
}
void ShowGrid::setLabelColor(const QString& labelColor)
{
m_currentLabelColor = labelColor;
TextSymbol* labelSymbol = static_cast<TextSymbol*>(m_grid->textSymbol(0));
labelSymbol->setColor(labelColor.toLower());
// Some grids have multiple levels, in this sample we set the same symbol for all levels
for (int level = 0; level < m_grid->levelCount(); ++level)
m_grid->setTextSymbol(level, labelSymbol);
emit labelColorChanged();
}
void ShowGrid::setLabelPosition(const QString& labelPosition)
{
m_currentLabelPosition = labelPosition;
if (labelPosition == s_geographic)
m_grid->setLabelPosition(GridLabelPosition::Geographic);
else if (labelPosition == s_bottomLeft)
m_grid->setLabelPosition(GridLabelPosition::BottomLeft);
else if (labelPosition == s_bottomRight)
m_grid->setLabelPosition(GridLabelPosition::BottomRight);
else if (labelPosition == s_topLeft)
m_grid->setLabelPosition(GridLabelPosition::TopLeft);
else if (labelPosition == s_topRight)
m_grid->setLabelPosition(GridLabelPosition::TopRight);
else if (labelPosition == s_center)
m_grid->setLabelPosition(GridLabelPosition::Center);
else if (labelPosition == s_allSides)
m_grid->setLabelPosition(GridLabelPosition::AllSides);
emit labelPositionChanged();
}
void ShowGrid::setLabelFormat(const QString& labelFormat)
{
m_currentLabelFormat = labelFormat;
// Only LatitudeLongitudeGrid supports label formats
if (m_grid->gridType() != GridType::LatitudeLongitudeGrid)
return;
if (labelFormat == s_decimalDegrees)
static_cast<LatitudeLongitudeGrid*>(m_grid)->setLabelFormat(LatitudeLongitudeGridLabelFormat::DecimalDegrees);
else if (labelFormat == s_degreesMinutesSeconds)
static_cast<LatitudeLongitudeGrid*>(m_grid)->setLabelFormat(LatitudeLongitudeGridLabelFormat::DegreesMinutesSeconds);
emit labelFormatChanged();
}