Calculate geodesic latitude/longitude from Maidenhead locator.

    Args:
        locator (str): Maidenhead locator string

    Returns:
        tuple of float: Geodesic latitude and longitude values

    Raises:
        ValueError: Incorrect grid locator length
        ValueError: Invalid values in locator string

def from_grid_locator(locator):
    """Calculate geodesic latitude/longitude from Maidenhead locator.

    Args:
        locator (str): Maidenhead locator string

    Returns:
        tuple of float: Geodesic latitude and longitude values

    Raises:
        ValueError: Incorrect grid locator length
        ValueError: Invalid values in locator string
    """
    if not len(locator) in (4, 6, 8):
        raise ValueError('Locator must be 4, 6 or 8 characters long %r'
                         % locator)

    # Convert the locator string to a list, because we need it to be mutable to
    # munge the values
    locator = list(locator)

    # Convert characters to numeric value, fields are always uppercase
    locator[0] = ord(locator[0]) - 65
    locator[1] = ord(locator[1]) - 65

    # Values for square are always integers
    locator[2] = int(locator[2])
    locator[3] = int(locator[3])

    if len(locator) >= 6:
        # Some people use uppercase for the subsquare data, in spite of
        # lowercase being the accepted style, so handle that too.
        locator[4] = ord(locator[4].lower()) - 97
        locator[5] = ord(locator[5].lower()) - 97

    if len(locator) == 8:
        # Extended square values are always integers
        locator[6] = int(locator[6])
        locator[7] = int(locator[7])

    # Check field values within 'A'(0) to 'R'(17), and square values are within
    # 0 to 9
    if not 0 <= locator[0] <= 17 \
       or not 0 <= locator[1] <= 17 \
       or not 0 <= locator[2] <= 9 \
       or not 0 <= locator[3] <= 9:
        raise ValueError('Invalid values in locator %r' % locator)

    # Check subsquare values are within 'a'(0) to 'x'(23)
    if len(locator) >= 6:
        if not 0 <= locator[4] <= 23 \
           or not 0 <= locator[5] <= 23:
            raise ValueError('Invalid values in locator %r' % locator)

    # Extended square values must be within 0 to 9
    if len(locator) == 8:
        if not 0 <= locator[6] <= 9 \
           or not 0 <= locator[7] <= 9:
            raise ValueError('Invalid values in locator %r' % locator)

    longitude = LONGITUDE_FIELD * locator[0] \
        + LONGITUDE_SQUARE * locator[2]
    latitude = LATITUDE_FIELD * locator[1] \
        + LATITUDE_SQUARE * locator[3]

    if len(locator) >= 6:
        longitude += LONGITUDE_SUBSQUARE * locator[4]
        latitude += LATITUDE_SUBSQUARE * locator[5]

    if len(locator) == 8:
        longitude += LONGITUDE_EXTSQUARE * locator[6] + LONGITUDE_EXTSQUARE / 2
        latitude += LATITUDE_EXTSQUARE * locator[7] + LATITUDE_EXTSQUARE / 2
    else:
        longitude += LONGITUDE_EXTSQUARE * 5
        latitude += LATITUDE_EXTSQUARE * 5

    # Rebase longitude and latitude to normal geodesic
    longitude -= 180
    latitude -= 90

    return latitude, longitude