Mgrs.parse constructor

Mgrs.parse(
  1. String text, {
  2. Datum datum = Datum.WGS84,
})

Parses a MGRS grid reference from a text string like '31U DQ 48251 11932'.

The input text should contains following elements:

  • grid zone designator (GZD), e.g. ‘31U’, where zone is 1-60 and band is C..X covering 80°S..84°N
  • 100km grid square letter-pair, e.g. ‘DQ’, where each letter represents 100km grid square column (‘e’) and row (‘n’) respectively
  • easting, e.g. ‘48251’ (metres)
  • northing, e.g. ‘11932’ (metres)

Use datum to set the datum for calculations with a reference ellipsoid and datum transformation parameters.

Throws FormatException if coordinates are invalid.

Examples:

  // The MGRS grid reference parsed from text (same as using the default
  // constructor `Mgrs(31, 'U', 'D', 'Q', 48251, 11932)`).
  final mgrsRef = Mgrs.parse('31U DQ 48251 11932');

  // Military style without separators.
  final mgrsRefMil = Mgrs.parse('31UDQ4825111932');

Implementation

factory Mgrs.parse(
  String text, {
  Datum datum = Datum.WGS84,
}) {
  // this shall contain: [ gzd, en100k, easting, northing ]
  List<String>? ref;

  // check for military-style grid reference with no separators
  final trimmed = text.trim();
  if (trimmed.length >= 6 && RegExp(r'\s+').allMatches(trimmed).isEmpty) {
    // no whitespace found and at least 6 characters, should contain also
    //easting and northing

    // convert mgrsGridRef to standard space-separated format
    final exp =
        RegExp(r'(\d\d?[A-Z])([A-Z]{2})([0-9]{2,10})', caseSensitive: false)
            .allMatches(text)
            .map((m) => m.groups([1, 2, 3]));
    if (exp.isEmpty) {
      throw FormatException('invalid MGRS grid reference `$text`');
    }
    final parsed = exp.first;

    final gzd = parsed[0]!;
    final en100k = parsed[1]!;
    final en = parsed[2]!;
    final easting = en.substring(0, en.length ~/ 2);
    final northing = en.substring(en.length ~/ 2);

    ref = [gzd, en100k, easting, northing];
  }

  // if ref still null then match separate elements (separated by whitespace)
  // the result should contain: [ gzd, en100k, easting, northing ]
  ref ??= trimmed.split(RegExp(r'\s+'));

  // check for 4 elements in MGRS grid reference
  if (ref.length != 4) {
    throw FormatException('invalid MGRS grid reference `$text`');
  }

  // split grid ref into gzd, en100k, e, n
  final gzd = ref[0];
  final en100k = ref[1];
  final e = ref[2];
  final n = ref[3];
  if (!(gzd.length == 2 || gzd.length == 3) || en100k.length != 2) {
    throw FormatException('invalid MGRS grid reference `$text`');
  }

  // split gzd into zone (one or two digits), band (one letter)
  final gzdLen = gzd.length;
  final lonZone = int.parse(gzd.substring(0, gzdLen - 1));
  final band = gzd.substring(gzdLen - 1, gzdLen);

  // split 100km letter-pair into column and row letters
  final column = en100k[0];
  final row = en100k[1];

  final easting = _parseCoordinate(e);
  final northing = _parseCoordinate(n);

  // use the default constructor as it also validates the coordinates (and
  // constructs also a MgrsGridSquare object)
  return Mgrs(
    lonZone,
    band,
    column,
    row,
    easting,
    northing,
    datum: datum,
  );
}