The Military Grid Reference System (MGRS) is the geocoordinate standard used by NATO militaries for locating points on Earth. The MGRS is derived from the Universal Transverse Mercator (UTM) grid system and the Universal Polar Stereographic (UPS) grid system, but uses a different labeling convention.

mgrs
Figure 1. The "MGRS grid" sample shows you how to use the MGRS API in LuciadRIA

Formatting and parsing points to/from MGRS

To format and parse LuciadRIA Points to/from MGRS strings, use @luciad/ria-milsym/text/mgrs/MGRSFormat.

Program: Use a MGRSFormat to format points to MGRS strings
const format = new MGRSFormat({
  formatType: MGRSFormatType.UTM_UPS,
  precision: MGRSFormatPrecision.PRECISION_1M,
  zoneSeparator: " ",
  coordinateSeparator: " "
});
const lonLatPoint = createPoint(getReference("CRS:84"), [10, 10]);
const mgrsString = format.format(lonLatPoint);
console.log(mgrsString); // 32P 0609600 1105578
const parsedPoint = format.parse(mgrsString);
console.log(parsedPoint);

For example, you can use this to show MGRS coordinates at the mouse location. See the "MGRS Grid" sample for a demonstration.

Visualizing an MGRS grid

You can visualize the MGRS grid by using @luciad/ria-milsym/grid/MGRSGrid and @luciad/ria/view/grid/GridLayer.

In order of increasing complexity, you can:

  • Use the default, out-of-the-box grid styling:

Program: Use the default MGRSGrid with a GridLayer to show an MGRS grid on the map
const mgrsGrid = createDefaultMGRSGrid();
const mgrsGridLayer = new GridLayer(mgrsGrid);
map.layerTree.addChild(mgrsGridLayer);
  • Do some basic tweaks to the default styling, like changing line and text colors. The "MGRS grid" sample also demonstrates this:

Program: Basic tweaks to the default MGRSGrid
const primaryColor = "rgb(255, 0, 0)";
const secondaryColor = "rgb(0, 255, 0)";
const tertiaryColor = "rgb(0, 0, 255)";
const mgrsGrid = createDefaultMGRSGrid({
  scaleMultiplier: 1.5, // make the grid more coarse
  primaryLineStyle: {color: primaryColor, width: 1},
  primaryLabelStyle: {font: "12px monospace", fill: primaryColor},
  secondaryLineStyle: {color: secondaryColor, width: 2},
  secondaryLabelStyle: {font: "14px monospace", fill: secondaryColor},
  tertiaryLineStyle: {color: tertiaryColor, width: 3},
  tertiaryLabelStyle: {font: "16px monospace", fill: tertiaryColor}
});
const mgrsGridLayer = new GridLayer(mgrsGrid);
map.layerTree.addChild(mgrsGridLayer);
  • Completely customize the styling of the MGRS grid:

Program: Completely custom MGRSGrid styling
// styling with completely custom scale ranges and styles

// always show GRID_ZONES with thick red lines, regardless of the zoom level
const gridZoneColor = "rgb(255, 0, 0)";
const gridZoneSetting = ({
  scaleRange: {min: 0, max: Number.POSITIVE_INFINITY},
  level: MGRSLevel.GRID_ZONES,
  lineStyle: {color: "rgb(255, 0, 0)", width: 5},
  labelStyle: {font: "20px monospace", fill: gridZoneColor}
});

// When zoomed in far enough, show 100KM grid squares in yellow.
// Hide them when zoomed in beyond the 10KM grid square scale range start
const startScale100Km = 1.0 / 3_000_000.0
const startScale10Km = 1.0 / 750_000.0;
const square100KmSetting = {
  scaleRange: {min: startScale100Km, max: startScale10Km},
  level: MGRSLevel.SQUARES_100KM,
  lineStyle: {color: "rgb(255,255,0)", width: 5},
  labelStyle: {font: "20px monospace", fill: gridZoneColor}
};

// when zoomed in beyond the 100km squares, show 10Km squares in green
const square10KmSetting = {
  scaleRange: {min: startScale10Km, max: Number.POSITIVE_INFINITY},
  level: MGRSLevel.SQUARES_10KM,
  lineStyle: {color: "rgb(0, 255, 0)", width: 2},
  labelStyle: {font: "20px monospace", fill: gridZoneColor}
};

// don't show any lower MGRS levels (SQUARES_1KM, SQUARES_100M, SQUARES_10M and SQUARES_1M)

const mgrsGrid = new MGRSGrid([gridZoneSetting, square100KmSetting, square10KmSetting]);
const mgrsGridLayer = new GridLayer(mgrsGrid);
map.layerTree.addChild(mgrsGridLayer);

Adding an MGRS overlay label to the map

When users zoom in far on the map, it’s easy for them to lose track of the grid zone or square that they’re in. To prevent that, you can show an overlay label on the map. This label shows the users which grid zone and square they have reached by zooming in on the map. When you use the overlay label combined with the grid labels and the mouse coordinate readout, you give the users more than one option for determining their current MGRS location.

mgrs overlay label
Figure 2. The MGRS Sample shows an overlay label at the top, when users zoom in. It informs the users that they zoomed in on the "31U" grid zone, in the "ES" square. The grid lines tell them the northing — 82-84 — and easting — 94-95 . The mouse coordinate readout at the bottom also gives them the exact longitude-latitude and MGRS coordinates under the mouse cursor.

The LuciadRIA API gives you a utility class to generate the text for the MGRS overlay label: @luciad/ria-milsym/grid/MGRSGridOverlayTextProvider. It fires events whenever the overlay label changes its text, or toggles its visibility. You can use this utility in a UI framework of your choice.

Program: An MGRS overlay label added to the map, using the DOM API. The "MGRS grid" sample shows you how to implement this in React.
// create a default MGRS grid layer
const mgrsGrid = createDefaultMGRSGrid();
const mgrsGridLayer = new GridLayer(mgrsGrid);
map.layerTree.addChild(mgrsGridLayer);

// create an overlay div element, centered at the top of the map
const overlayDiv = document.createElement("div");
overlayDiv.id = "mgrs-overlay-div";
overlayDiv.style.zIndex = "10";
overlayDiv.style.position = "absolute";
overlayDiv.style.top = "15px";
overlayDiv.style.left = "50%";
overlayDiv.style.transform = "translate(-50%, 0)";
overlayDiv.style.color = "yellow";
overlayDiv.style.fontSize = "3em";
overlayDiv.style.pointerEvents = "none";
map.domNode.appendChild(overlayDiv);

// create a MGRS overlay text provider
const overlaySettings = createDefaultMGRSOverlayTextSettings(mgrsGrid);
const overlayTextProvider = new MGRSGridOverlayTextProvider(mgrsGridLayer, overlaySettings,{coordinate: OverlayTextCoordinateType.COMMON_MAP_COORDINATE});

overlayDiv.style.display = "none"
const visibilityChangedHandle = overlayTextProvider.on("VisibilityChanged", () => {
  overlayDiv.style.display = "block";
});

overlayDiv.innerText = overlayTextProvider.text;
const textChangedHandle = overlayTextProvider.on("TextChanged", () => {
  overlayDiv.innerText = overlayTextProvider.text;
});

function destroyUI() {
  visibilityChangedHandle.remove();
  textChangedHandle.remove();
  overlayTextProvider.destroy();
  map.domNode.removeChild(overlayDiv);
}