def _find_one_centroid_distance(storm_x_vertices_metres,
                                storm_y_vertices_metres,
                                warning_polygon_object_xy):
    """Finds distance between one storm object and one warning.

    V = number of vertices in storm outline

    :param storm_x_vertices_metres: length-V numpy array of x-coordinates.
    :param storm_y_vertices_metres: length-V numpy array of y-coordinates.
    :param warning_polygon_object_xy: Polygon (instance of
        `shapely.geometry.Polygon`) with x-y coordinates of warning boundary.
    :return: distance_metres: Distance between storm object and warning (minimum
        distance to polygon interior over all storm vertices).
    """

    centroid_x_metres = numpy.mean(storm_x_vertices_metres)
    centroid_y_metres = numpy.mean(storm_y_vertices_metres)

    pip_flag = polygons.point_in_or_on_polygon(
        polygon_object=warning_polygon_object_xy,
        query_x_coordinate=centroid_x_metres,
        query_y_coordinate=centroid_y_metres)

    if pip_flag:
        return 0.

    point_object = shapely.geometry.Point(centroid_x_metres, centroid_y_metres)
    return point_object.distance(warning_polygon_object_xy)
def _find_one_polygon_distance(storm_x_vertices_metres,
                               storm_y_vertices_metres,
                               warning_polygon_object_xy):
    """Finds distance between one storm object and one warning.

    V = number of vertices in storm outline

    :param storm_x_vertices_metres: length-V numpy array of x-coordinates.
    :param storm_y_vertices_metres: length-V numpy array of y-coordinates.
    :param warning_polygon_object_xy: Polygon (instance of
        `shapely.geometry.Polygon`) with x-y coordinates of warning boundary.
    :return: distance_metres: Distance between storm object and warning (minimum
        distance to polygon interior over all storm vertices).
    """

    num_vertices = len(storm_x_vertices_metres)
    distance_metres = LARGE_NUMBER

    for k in range(num_vertices):
        this_flag = polygons.point_in_or_on_polygon(
            polygon_object=warning_polygon_object_xy,
            query_x_coordinate=storm_x_vertices_metres[k],
            query_y_coordinate=storm_y_vertices_metres[k])

        if this_flag:
            return 0.

        this_point_object = shapely.geometry.Point(storm_x_vertices_metres[k],
                                                   storm_y_vertices_metres[k])
        this_distance_metres = this_point_object.distance(
            warning_polygon_object_xy)
        distance_metres = numpy.minimum(distance_metres, this_distance_metres)

    return distance_metres
    def test_point_in_or_on_polygon_inside(self):
        """Ensures correct output from point_in_or_on_polygon.

        In this case, answer = True (point inside polygon).
        """

        this_flag = polygons.point_in_or_on_polygon(
            POLYGON_OBJECT_EXCL_BUFFER_XY_METRES,
            query_x_coordinate=X_IN_NESTED_BUFFER,
            query_y_coordinate=Y_IN_NESTED_BUFFER)
        self.assertTrue(this_flag)
    def test_point_in_or_on_polygon_false(self):
        """Ensures correct output from point_in_or_on_polygon.

        In this case, answer = False.
        """

        this_flag = polygons.point_in_or_on_polygon(
            POLYGON_OBJECT_EXCL_BUFFER_XY_METRES,
            query_x_coordinate=X_OUTSIDE_NESTED_BUFFER,
            query_y_coordinate=Y_OUTSIDE_NESTED_BUFFER)
        self.assertFalse(this_flag)
示例#5
0
def _polygons_to_mask_one_panel(polygon_objects_grid_coords, num_grid_rows,
                                num_grid_columns):
    """Converts list of polygons to binary mask.

    M = number of rows in grid
    N = number of columns in grid

    :param polygon_objects_grid_coords: See doc for
        `polygons_from_pixel_to_grid_coords`.
    :param num_grid_rows: Same.
    :param num_grid_columns: Same.
    :return: mask_matrix: M-by-N numpy array of Boolean flags.  If
        mask_matrix[i, j] == True, grid point [i, j] is in/on at least one of
        the polygons.
    """

    mask_matrix = numpy.full((num_grid_rows, num_grid_columns),
                             False,
                             dtype=bool)

    num_polygons = len(polygon_objects_grid_coords)
    if num_polygons == 0:
        return mask_matrix

    # TODO(thunderhoser): This triple for-loop is probably inefficient.
    for k in range(num_polygons):
        these_grid_columns = numpy.array(
            polygon_objects_grid_coords[k].exterior.xy[0])

        error_checking.assert_is_geq_numpy_array(these_grid_columns, -0.5)
        error_checking.assert_is_leq_numpy_array(these_grid_columns,
                                                 num_grid_columns - 0.5)

        these_grid_rows = numpy.array(
            polygon_objects_grid_coords[k].exterior.xy[1])

        error_checking.assert_is_geq_numpy_array(these_grid_rows, -0.5)
        error_checking.assert_is_leq_numpy_array(these_grid_rows,
                                                 num_grid_rows - 0.5)

        for i in range(num_grid_rows):
            for j in range(num_grid_columns):
                if mask_matrix[i, j]:
                    continue

                mask_matrix[i, j] = polygons.point_in_or_on_polygon(
                    polygon_object=polygon_objects_grid_coords[k],
                    query_x_coordinate=j,
                    query_y_coordinate=i)

    return mask_matrix
def find_points_in_conus(conus_latitudes_deg,
                         conus_longitudes_deg,
                         query_latitudes_deg,
                         query_longitudes_deg,
                         use_shortcuts=True,
                         verbose=False):
    """Finds points in CONUS.

    Q = number of query points

    This method assumes that the domain doesn't wrap around 0 deg E (Greenwich).

    If you set `use_shortcuts = True`, this method will assume that input
    coordinates `conus_latitudes_deg` and `conus_longitudes_deg` have been
    eroded by less than 100 km.

    :param conus_latitudes_deg: See doc for `_check_boundary`.
    :param conus_longitudes_deg: Same.
    :param query_latitudes_deg: length-Q numpy with latitudes (deg N) of query
        points.
    :param query_longitudes_deg: length-Q numpy with longitudes (deg E) of query
        points.
    :param use_shortcuts: Boolean flag.  If True, will use shortcuts to speed up
        calculation.
    :param verbose: Boolean flag.  If True, will print progress messages to
        command window.
    :return: in_conus_flags: length-Q numpy array of Boolean flags.
    """

    conus_longitudes_deg = _check_boundary(latitudes_deg=conus_latitudes_deg,
                                           longitudes_deg=conus_longitudes_deg)
    query_longitudes_deg = _check_boundary(latitudes_deg=query_latitudes_deg,
                                           longitudes_deg=query_longitudes_deg)
    error_checking.assert_is_boolean(use_shortcuts)
    error_checking.assert_is_boolean(verbose)

    num_query_points = len(query_latitudes_deg)
    in_conus_flags = numpy.full(num_query_points, -1, dtype=int)

    if use_shortcuts:

        # Use rectangle.
        latitude_flags = numpy.logical_and(
            query_latitudes_deg >= SHORTCUT_BOX_LATITUDES_DEG[0],
            query_latitudes_deg <= SHORTCUT_BOX_LATITUDES_DEG[1])
        longitude_flags = numpy.logical_and(
            query_longitudes_deg >= SHORTCUT_BOX_LONGITUDES_DEG[0],
            query_longitudes_deg <= SHORTCUT_BOX_LONGITUDES_DEG[1])
        in_conus_flags[numpy.logical_and(latitude_flags, longitude_flags)] = 1

        # Use simplified eroded boundary.
        module_dir_name = os.path.dirname(__file__)
        parent_dir_name = '/'.join(module_dir_name.split('/')[:-1])
        inner_boundary_file_name = (
            '{0:s}/conus_polygon_100-km-eroded.nc'.format(parent_dir_name))

        inner_conus_latitudes_deg, inner_conus_longitudes_deg = (
            read_from_netcdf(inner_boundary_file_name))
        trial_indices = numpy.where(in_conus_flags == -1)[0]

        these_flags = find_points_in_conus(
            conus_latitudes_deg=inner_conus_latitudes_deg,
            conus_longitudes_deg=inner_conus_longitudes_deg,
            query_latitudes_deg=query_latitudes_deg[trial_indices],
            query_longitudes_deg=query_longitudes_deg[trial_indices],
            use_shortcuts=False)
        these_indices = trial_indices[numpy.where(these_flags)]
        in_conus_flags[these_indices] = 1

        # Use simplified dilated boundary.
        module_dir_name = os.path.dirname(__file__)
        parent_dir_name = '/'.join(module_dir_name.split('/')[:-1])
        outer_boundary_file_name = (
            '{0:s}/conus_polygon_100-km-dilated.nc'.format(parent_dir_name))

        outer_conus_latitudes_deg, outer_conus_longitudes_deg = (
            read_from_netcdf(outer_boundary_file_name))
        trial_indices = numpy.where(in_conus_flags == -1)[0]

        these_flags = find_points_in_conus(
            conus_latitudes_deg=outer_conus_latitudes_deg,
            conus_longitudes_deg=outer_conus_longitudes_deg,
            query_latitudes_deg=query_latitudes_deg[trial_indices],
            query_longitudes_deg=query_longitudes_deg[trial_indices],
            use_shortcuts=False)
        these_indices = trial_indices[numpy.where(numpy.invert(these_flags))]
        in_conus_flags[these_indices] = 0

    conus_polygon_object = polygons.vertex_arrays_to_polygon_object(
        exterior_x_coords=conus_longitudes_deg,
        exterior_y_coords=conus_latitudes_deg)

    for i in range(num_query_points):
        if numpy.mod(i, 1000) == 0 and verbose:
            print(('Have done point-in-CONUS test for {0:d} of {1:d} points...'
                   ).format(i, num_query_points))

        if in_conus_flags[i] != -1:
            continue

        in_conus_flags[i] = polygons.point_in_or_on_polygon(
            polygon_object=conus_polygon_object,
            query_x_coordinate=query_longitudes_deg[i],
            query_y_coordinate=query_latitudes_deg[i])

    if verbose:
        print('Have done point-in-CONUS test for all {0:d} points!'.format(
            num_query_points))

    return in_conus_flags.astype(bool)