Esempio n. 1
0
def _intersection(w1, w2):
    """ Compute intersection of window 1 and window 2"""
    coeffs = _compute_intersection(w1, w2)
    if coeffs[2] > 0 and coeffs[3] > 0:
        return Window(*coeffs)
    else:
        raise WindowError(f"Intersection is empty {w1} {w2}")
Esempio n. 2
0
    def round_offsets(self, op='floor', pixel_precision=None):
        """Return a copy with column and row offsets rounded.

        Offsets are rounded to the nearest whole number. The lengths
        are not changed.

        Parameters
        ----------
        op : str
            'ceil' or 'floor'
        pixel_precision : int, optional (default: None)
            Number of places of rounding precision.

        Returns
        -------
        Window
        """
        operator = getattr(math, op, None)
        if not operator:
            raise WindowError("operator must be 'ceil' or 'floor'")
        else:
            return Window(
                operator(round(self.col_off, pixel_precision) if
                         pixel_precision is not None else self.col_off),
                operator(round(self.row_off, pixel_precision) if
                         pixel_precision is not None else self.row_off),
                self.width, self.height)
Esempio n. 3
0
    def round_offsets(self, op='floor', pixel_precision=None):
        """Return a copy with column and row offsets rounded.

        Offsets are rounded to the preceding (floor) or succeeding (ceil)
        whole number. The lengths are not changed.

        Parameters
        ----------
        op : str
            'ceil' or 'floor'
        pixel_precision : int, optional (default: None)
            Number of places of rounding precision.

        Returns
        -------
        Window
        """
        if op not in {'ceil', 'floor'}:
            raise WindowError("operator must be 'ceil' or 'floor', got '{}'".format(op))

        operator = getattr(math, op)
        if pixel_precision is None:
            return Window(operator(self.col_off), operator(self.row_off),
                          self.width, self.height)
        else:
            return Window(operator(round(self.col_off, pixel_precision)),
                          operator(round(self.row_off, pixel_precision)),
                          self.width, self.height)
Esempio n. 4
0
    def round_lengths(self, op='floor', pixel_precision=None):
        """Return a copy with width and height rounded.

        Lengths are rounded to the preceding (floor) or succeeding (ceil)
        whole number. The offsets are not changed.

        Parameters
        ----------
        op: str
            'ceil' or 'floor'
        pixel_precision: int, optional (default: None)
            Number of places of rounding precision.

        Returns
        -------
        Window
        """
        operator = getattr(math, op, None)
        if not operator:
            raise WindowError("operator must be 'ceil' or 'floor'")
        else:
            return Window(
                self.col_off, self.row_off,
                operator(
                    round(self.width, pixel_precision
                          ) if pixel_precision is not None else self.width),
                operator(
                    round(self.height, pixel_precision
                          ) if pixel_precision is not None else self.height))
Esempio n. 5
0
def intersection(*windows):
    """Innermost extent of window intersections.

    Will raise WindowError if windows do not intersect.

    Parameters
    ----------
    windows: sequence
        One or more Windows.

    Returns
    -------
    Window
    """
    if not intersect(windows):
        raise WindowError("windows do not intersect")

    stacked = np.dstack([toranges(w) for w in windows])
    row_start, row_stop = stacked[0, 0].max(), stacked[0, 1].min()
    col_start, col_stop = stacked[1, 0].max(), stacked[1, 1].min()
    return Window(
        col_off=col_start,
        row_off=row_start,
        width=col_stop - col_start,
        height=row_stop - row_start,
    )
Esempio n. 6
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform=None,
                height=None,
                width=None,
                precision=None):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left, bottom, right, top: float
        Left (west), bottom (south), right (east), and top (north)
        bounding coordinates.
    transform: Affine, required
        Affine transform matrix.
    height, width: int, required
        Number of rows and columns of the window.
    precision: int, optional
        Number of decimal points of precision when computing inverse
        transform.

    Returns
    -------
    Window
        A new Window.

    Raises
    ------
    WindowError
        If a window can't be calculated.

    """
    if not isinstance(transform, Affine):  # TODO: RPCs?
        raise WindowError(
            "A transform object is required to calculate the window")

    row_start, col_start = rowcol(transform,
                                  left,
                                  top,
                                  op=float,
                                  precision=precision)

    row_stop, col_stop = rowcol(transform,
                                right,
                                bottom,
                                op=float,
                                precision=precision)

    return Window.from_slices((row_start, row_stop), (col_start, col_stop),
                              height=height,
                              width=width,
                              boundless=True)
Esempio n. 7
0
def get_data_window(arr, nodata=None):
    """Window covering the input array's valid data pixels.

    Parameters
    ----------
    arr: numpy ndarray, <= 3 dimensions
    nodata: number
        If None, will either return a full window if arr is not a masked
        array, or will use the mask to determine non-nodata pixels.
        If provided, it must be a number within the valid range of the
        dtype of the input array.

    Returns
    -------
    Window
    """

    num_dims = len(arr.shape)
    if num_dims > 3:
        raise WindowError(
            "get_data_window input array must have no more than "
            "3 dimensions")

    if nodata is None:
        if not hasattr(arr, 'mask'):
            return Window.from_slices((0, arr.shape[-2]), (0, arr.shape[-1]))
    else:
        arr = np.ma.masked_array(arr, arr == nodata)

    if num_dims == 2:
        data_rows, data_cols = np.where(np.equal(arr.mask, False))
    else:
        data_rows, data_cols = np.where(
            np.any(np.equal(np.rollaxis(arr.mask, 0, 3), False), axis=2))

    if data_rows.size:
        row_range = (data_rows.min(), data_rows.max() + 1)
    else:
        row_range = (0, 0)

    if data_cols.size:
        col_range = (data_cols.min(), data_cols.max() + 1)
    else:
        col_range = (0, 0)

    return Window.from_slices(row_range, col_range)
Esempio n. 8
0
def intersection(*windows):
    """Innermost extent of window intersections.

    Will raise WindowError if windows do not intersect.

    Parameters
    ----------
    windows: sequence
        One or more Windows.

    Returns
    -------
    Window
    """
    if not intersect(windows):
        raise WindowError("windows do not intersect")

    stacked = np.dstack([toranges(w) for w in windows])
    return Window.from_slices((stacked[0, 0].max(), stacked[0, 1].min()),
                              (stacked[1, 0].max(), stacked[1, 1].min()))
Esempio n. 9
0
    def round_lengths(self, op='floor', pixel_precision=3):
        """Return a copy with width and height rounded.

        Lengths are rounded to the nearest whole number. The offsets
        are not changed.

        Parameters
        ----------
        op: str
            'ceil' or 'floor'
        pixel_precision: int
            Number of places of rounding precision.

        Returns
        -------
        Window
        """
        operator = getattr(math, op, None)
        if not operator:
            raise WindowError("operator must be 'ceil' or 'floor'")
        else:
            return Window(self.col_off, self.row_off,
                          operator(round(self.width, pixel_precision)),
                          operator(round(self.height, pixel_precision)))
Esempio n. 10
0
def round_window_to_full_blocks(window, block_shapes, height=0, width=0):
    """Round window to include full expanse of intersecting tiles.

    Parameters
    ----------
    window: Window
        The input window.

    block_shapes : tuple of block shapes
        The input raster's block shape. All bands must have the same
        block/stripe structure

    Returns
    -------
    Window
    """
    if len(set(block_shapes)) != 1:  # pragma: no cover
        raise WindowError(
            "All bands must have the same block/stripe structure")

    window = evaluate(window, height=height, width=width)

    height_shape = block_shapes[0][0]
    width_shape = block_shapes[0][1]

    (row_start, row_stop), (col_start, col_stop) = window.toranges()

    row_min = int(row_start // height_shape) * height_shape
    row_max = int(row_stop // height_shape) * height_shape + \
        (height_shape if row_stop % height_shape != 0 else 0)

    col_min = int(col_start // width_shape) * width_shape
    col_max = int(col_stop // width_shape) * width_shape + \
        (width_shape if col_stop % width_shape != 0 else 0)

    return Window(col_min, row_min, col_max - col_min, row_max - row_min)
Esempio n. 11
0
    def from_slices(cls, rows, cols, height=-1, width=-1, boundless=False):
        """Construct a Window from row and column slices or tuples.

        Parameters
        ----------
        rows, cols: slice or tuple
            Slices or 2-tuples containing start, stop indexes.
        height, width: float
            A shape to resolve relative values against.
        boundless: bool, optional
            Whether the inputs are bounded or bot.

        Returns
        -------
        Window
        """
        # Convert the rows indexing obj to offset and height.
        # Normalize to slices
        if not isinstance(rows, (tuple, slice)):
            raise WindowError("rows must be a tuple or slice")
        else:
            rows = slice(*rows) if isinstance(rows, tuple) else rows

        # Resolve the window height.
        # Fail if the stop value is relative or implicit and there
        # is no height context.
        if not boundless and (
                (rows.start is not None and rows.start < 0) or
                rows.stop is None or rows.stop < 0) and height < 0:
            raise WindowError(
                "A non-negative height is required")

        row_off = rows.start or 0.0
        if not boundless and row_off < 0:
            row_off += height

        row_stop = height if rows.stop is None else rows.stop
        if not boundless and row_stop < 0:
            row_stop += height

        num_rows = row_stop - row_off

        # Number of rows is never less than 0.
        num_rows = max(num_rows, 0.0)

        # Do the same for the cols indexing object.
        if not isinstance(cols, (tuple, slice)):
            raise WindowError("cols must be a tuple or slice")
        else:
            cols = slice(*cols) if isinstance(cols, tuple) else cols

        if not boundless and (
                (cols.start is not None and cols.start < 0) or
                cols.stop is None or cols.stop < 0) and width < 0:
            raise WindowError("A non-negative width is required")

        col_off = cols.start or 0.0
        if not boundless and col_off < 0:
            col_off += width

        col_stop = width if cols.stop is None else cols.stop
        if not boundless and col_stop < 0:
            col_stop += width

        num_cols = col_stop - col_off
        num_cols = max(num_cols, 0.0)

        return cls(col_off=col_off, row_off=row_off, width=num_cols,
                   height=num_rows)
Esempio n. 12
0
    def from_slices(cls, rows, cols, height=-1, width=-1, boundless=False):
        """Construct a Window from row and column slices or tuples / lists of
        start and stop indexes. Converts the rows and cols to offsets, height,
        and width.

        In general, indexes are defined relative to the upper left corner of
        the dataset: rows=(0, 10), cols=(0, 4) defines a window that is 4
        columns wide and 10 rows high starting from the upper left.

        Start indexes may be `None` and will default to 0.
        Stop indexes may be `None` and will default to width or height, which
        must be provided in this case.

        Negative start indexes are evaluated relative to the lower right of the
        dataset: rows=(-2, None), cols=(-2, None) defines a window that is 2
        rows high and 2 columns wide starting from the bottom right.

        Parameters
        ----------
        rows, cols: slice, tuple, or list
            Slices or 2 element tuples/lists containing start, stop indexes.
        height, width: float
            A shape to resolve relative values against. Only used when a start
            or stop index is negative or a stop index is None.
        boundless: bool, optional
            Whether the inputs are bounded (default) or not.

        Returns
        -------
        Window
        """

        # Normalize to slices
        if isinstance(rows, (tuple, list)):
            if len(rows) != 2:
                raise WindowError("rows must have a start and stop index")
            rows = slice(*rows)

        elif not isinstance(rows, slice):
            raise WindowError("rows must be a slice, tuple, or list")

        if isinstance(cols, (tuple, list)):
            if len(cols) != 2:
                raise WindowError("cols must have a start and stop index")
            cols = slice(*cols)

        elif not isinstance(cols, slice):
            raise WindowError("cols must be a slice, tuple, or list")

        # Height and width are required if stop indices are implicit
        if rows.stop is None and height < 0:
            raise WindowError("height is required if row stop index is None")

        if cols.stop is None and width < 0:
            raise WindowError("width is required if col stop index is None")

        # Convert implicit indices to offsets, height, and width
        row_off = 0.0 if rows.start is None else rows.start
        row_stop = height if rows.stop is None else rows.stop

        col_off = 0.0 if cols.start is None else cols.start
        col_stop = width if cols.stop is None else cols.stop

        if not boundless:
            if (row_off < 0 or row_stop < 0):
                if height < 0:
                    raise WindowError("height is required when providing "
                                      "negative indexes")

                if row_off < 0:
                    row_off += height

                if row_stop < 0:
                    row_stop += height

            if (col_off < 0 or col_stop < 0):
                if width < 0:
                    raise WindowError("width is required when providing "
                                      "negative indexes")

                if col_off < 0:
                    col_off += width

                if col_stop < 0:
                    col_stop += width

        num_cols = max(col_stop - col_off, 0.0)
        num_rows = max(row_stop - row_off, 0.0)

        return cls(col_off=col_off,
                   row_off=row_off,
                   width=num_cols,
                   height=num_rows)
Esempio n. 13
0
def from_bounds(left,
                bottom,
                right,
                top,
                transform=None,
                height=None,
                width=None,
                precision=None):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left: float, required
        Left (west) bounding coordinates
    bottom: float, required
        Bottom (south) bounding coordinates
    right: float, required
        Right (east) bounding coordinates
    top: float, required
        Top (north) bounding coordinates
    transform: Affine, required
        Affine transform matrix.
    precision, height, width: int, optional
        These parameters are unused, deprecated in rasterio 1.3.0, and
        will be removed in version 2.0.0.

    Returns
    -------
    Window
        A new Window.

    Raises
    ------
    WindowError
        If a window can't be calculated.

    """
    if height is not None or width is not None or precision is not None:
        warnings.warn(
            "The height, width, and precision parameters are unused, deprecated, and will be removed in 2.0.0.",
            RasterioDeprecationWarning,
        )

    if not isinstance(transform, Affine):  # TODO: RPCs?
        raise WindowError(
            "A transform object is required to calculate the window")
    if (right - left) / transform.a < 0:
        raise WindowError("Bounds and transform are inconsistent")
    if (bottom - top) / transform.e < 0:
        raise WindowError("Bounds and transform are inconsistent")

    rows, cols = rowcol(
        transform,
        [left, right, right, left],
        [top, top, bottom, bottom],
        op=float,
    )
    row_start, row_stop = min(rows), max(rows)
    col_start, col_stop = min(cols), max(cols)

    return Window(
        col_off=col_start,
        row_off=row_start,
        width=max(col_stop - col_start, 0.0),
        height=max(row_stop - row_start, 0.0),
    )
Esempio n. 14
0
def from_bounds(
    left, bottom, right, top, transform=None, height=None, width=None, precision=None
):
    """Get the window corresponding to the bounding coordinates.

    Parameters
    ----------
    left: float, required
        Left (west) bounding coordinates
    bottom: float, required
        Bottom (south) bounding coordinates
    right: float, required
        Right (east) bounding coordinates
    top: float, required
        Top (north) bounding coordinates
    transform: Affine, required
        Affine transform matrix.
    height: int, required
        Number of rows of the window.
    width: int, required
        Number of columns of the window.
    precision: int or float, optional
        An integer number of decimal points of precision when computing
        inverse transform, or an absolute float precision.

    Returns
    -------
    Window
        A new Window.

    Raises
    ------
    WindowError
        If a window can't be calculated.

    """
    if not isinstance(transform, Affine):  # TODO: RPCs?
        raise WindowError("A transform object is required to calculate the window")

    if (right - left) / transform.a < 0:
        raise WindowError("Bounds and transform are inconsistent")

    if (bottom - top) / transform.e < 0:
        raise WindowError("Bounds and transform are inconsistent")

    rows, cols = rowcol(
        transform,
        [left, right, right, left],
        [top, top, bottom, bottom],
        op=float,
        precision=precision,
    )
    row_start, row_stop = min(rows), max(rows)
    col_start, col_stop = min(cols), max(cols)

    return Window(
        col_off=col_start,
        row_off=row_start,
        width=max(col_stop - col_start, 0.0),
        height=max(row_stop - row_start, 0.0),
    )