Example #1
0
def test_for_errors(
    name: str,
    lat_lon_to_x_z: Transformer,
    x_z_to_lat_lon: Transformer,
    coords: Coordinates,
) -> bool:
    errors = False

    x, z = lat_lon_to_x_z.transform(coords.latitude, coords.longitude)
    if not math.isclose(x, coords.x) or not math.isclose(z, coords.z):
        error_x = x - coords.x
        error_z = z - coords.z
        error_pct_x = error_x / coords.x * 100
        error_pct_z = error_z / coords.z * 100
        print(f"{name} has error of {error_pct_x}% {error_pct_z}%")
        errors = True

    lat, lon = x_z_to_lat_lon.transform(coords.x, coords.z)
    if not math.isclose(lat, coords.latitude) or not math.isclose(
            lon, coords.longitude):
        error_lat = lat - coords.latitude
        error_lon = lon - coords.longitude
        error_pct_lon = error_lat / coords.latitude * 100
        error_pct_lat = error_lon / coords.longitude * 100
        print(f"{name} has error of {error_pct_lat}% {error_pct_lon}%")
        errors = True

    return errors
Example #2
0
def _split_points_along_anti_meridian(
        wgs84_to_proj: Transformer,
        points: List[Tuple[float, float]],
        threshold=0.01) -> List[List[Tuple[float, float]]]:
    total_points = len(points)
    groups: List = []
    group: List[Tuple[float, float]] = []
    for i in range(len(points)):
        current_point = points[i]
        next_point = points[(i + 1) % total_points]

        group.append(current_point)

        if abs(current_point[1] - next_point[1]) > 90:
            longitude = _sign(points[i][1]) * 180
            anti_meridian_at_current_lat = wgs84_to_proj.transform(
                current_point[0], 180)
            anti_meridian_at_next_lat = wgs84_to_proj.transform(
                next_point[0], 180)
            if anti_meridian_at_current_lat[0] == float('inf') and \
                    anti_meridian_at_next_lat[0] == float('inf'):
                error = (
                    'The anti-meridian at between the latitudes ' +
                    "%f and %f " % (current_point[0], next_point[0]) +
                    'could not be transformed with the projection. This is ' +
                    'unexpected. Please fix the algorithm!')
                raise RuntimeError(error)

            if anti_meridian_at_current_lat[0] == float('inf'):
                latitude = _binary_search_edge_wgs84(
                    wgs84_to_proj,
                    next_point[0],  # Valid latitude
                    current_point[0],  # Invalid latitude
                    threshold)
            elif anti_meridian_at_next_lat[0] == float('inf'):
                latitude = _binary_search_edge_wgs84(
                    wgs84_to_proj,
                    current_point[0],  # Valid latitude
                    next_point[0],  # Invalid latitude
                    threshold)
            else:
                latitude = next_point[0]

            if not math.isclose(current_point[1], longitude, abs_tol=0.0001):
                group.append((latitude, longitude))

            groups.append(group)

            group = []
            if not math.isclose(next_point[1], -longitude, abs_tol=0.0001):
                group.append((latitude, -longitude))

        if len(groups) != 0 and groups[0][0] == next_point:
            group.extend(groups[0])
            groups[0] = group
        elif i == total_points - 1:
            groups.append(group)

    return groups
Example #3
0
def _covers_hemisphere(wgs84_to_proj: Transformer) -> bool:
    covers_northern = wgs84_to_proj.transform(90, 0)[0] != float('inf')
    covers_southern = wgs84_to_proj.transform(-90, 0)[0] != float('inf')

    # We don't really support projections like this, where the north and south
    # poles are visible at the same, but it is possible in azimuthal
    # projections where the lat_0 is 0. For our purposes, we don't consider
    # this projection as covering both hemisphere; it merely touches it.
    if covers_northern and covers_southern:
        return False
    return covers_northern or covers_southern
Example #4
0
def calculate_raster_coordinate(
        longitude: float,
        latitude: float,
        padf_transform: List[float],
        transformer: Transformer):
    """ From a given longitude and latitude, calculate the raster coordinate corresponding to the
    top left point of the grid surrounding the given geographic coordinate.
    """
    # Because not all model types use EPSG:4269 projection, we first convert longitude and latitude
    # to whichever projection and coordinate system the grib file is using
    raster_long, raster_lat = transformer.transform(longitude, latitude)

    # Calculate the j index for point i,j in the grib file
    x_numerator = (raster_long - padf_transform[0] - raster_lat/padf_transform[5] *
                   padf_transform[2] + padf_transform[3] / padf_transform[5] *
                   padf_transform[2]) / padf_transform[1]

    y_numerator = (raster_lat - padf_transform[3] - raster_long/padf_transform[1] *
                   padf_transform[4] + padf_transform[0] / padf_transform[1] *
                   padf_transform[4]) / padf_transform[5]

    denominator = 1 - \
        padf_transform[4]/padf_transform[5]*padf_transform[2]/padf_transform[1]

    i_index = math.floor(x_numerator/denominator)
    j_index = math.floor(y_numerator/denominator)

    return (i_index, j_index)
Example #5
0
def calculate_geographic_coordinate(
        point: Tuple[int],
        padf_transform: List[float],
        transformer: Transformer):
    """ Calculate the geographic coordinates for a given points """
    x_coordinate = padf_transform[0] + point[0] * \
        padf_transform[1] + point[1]*padf_transform[2]
    y_coordinate = padf_transform[3] + point[0] * \
        padf_transform[4] + point[1]*padf_transform[5]

    lon, lat = transformer.transform(x_coordinate, y_coordinate)
    return (lon, lat)
Example #6
0
def _binary_search_edge_crs(transformer: Transformer,
                            angle: float,
                            threshold=1) -> float:
    min_r = 0
    crs = transformer.source_crs
    if crs.coordinate_operation.method_name == 'Orthographic':
        # Speeds up binary search a bit
        min_r = min(crs.ellipsoid.semi_minor_metre,
                    crs.ellipsoid.semi_major_metre) * 0.9

    max_r = max(crs.ellipsoid.semi_minor_metre, crs.ellipsoid.semi_major_metre)
    while max_r - min_r > threshold:
        pivot_r = (min_r + max_r) / 2
        x = math.cos(angle) * pivot_r
        y = math.sin(angle) * pivot_r
        if (transformer.transform(x, y))[0] == float('inf'):
            max_r = pivot_r
        else:
            min_r = pivot_r

    return min_r
Example #7
0
def _binary_search_edge_wgs84(
    wgs84_to_proj: Transformer,
    valid_lat: float,
    invalid_lat: float,
    threshold=0.01,
) -> float:
    """
    :param wgs84_to_proj:
    :param valid_lat:
    :param invalid_lat:
    :param threshold: Defaults to 0.01, since this level of precision usually
                      is the size of a neighbourhood.
                      See https://xkcd.com/2170/
    :return:
    """

    while abs(valid_lat - invalid_lat) > threshold:
        pivot_lat = (invalid_lat + valid_lat) / 2
        if (wgs84_to_proj.transform(pivot_lat, 180))[0] == float('inf'):
            invalid_lat = pivot_lat
        else:
            valid_lat = pivot_lat

    return valid_lat
 def transform(tf: Transformer, cell):
     return tf.transform(cell[0], cell[1])