def transform(src_crs, dst_crs, xs, ys, zs=None): """Transform vectors from source to target coordinate reference system. Transform vectors of x, y and optionally z from source coordinate reference system into target. Parameters ------------ src_crs: CRS or dict Source coordinate reference system, as a rasterio CRS object. Example: CRS({'init': 'EPSG:4326'}) dst_crs: CRS or dict Target coordinate reference system. xs: array_like Contains x values. Will be cast to double floating point values. ys: array_like Contains y values. zs: array_like, optional Contains z values. Assumed to be all 0 if absent. Returns --------- out: tuple of array_like, (xs, ys, [zs]) Tuple of x, y, and optionally z vectors, transformed into the target coordinate reference system. """ if len(xs) != len(ys): raise TransformError("xs and ys arrays must be the same length") elif zs is not None and len(xs) != len(zs): raise TransformError("zs, xs, and ys arrays must be the same length") if len(xs) == 0: return ([], [], []) if zs is not None else ([], []) else: return _transform(src_crs, dst_crs, xs, ys, zs)
def rowcol(self, xs, ys, zs=None, op=math.floor, precision=None): """ Returns rows and cols coordinates given geographic coordinates Parameters ---------- xs, ys : float or list of float Geographic coordinates zs : float or list of float, optional Height associated with coordinates. Primarily used for RPC based coordinate transformations. Ignored for affine based transformations. Default: 0. op : function, optional (default: math.floor) Function to convert fractional pixels to whole numbers (floor, ceiling, round) precision : int, optional (default: None) Decimal places of precision in indexing, as in `round()`. Raises ------ ValueError If input coordinates are not all equal length Returns ------- tuple of float or list of float """ AS_ARR = True if hasattr(xs, "__iter__") else False xs, ys, zs = self._ensure_arr_input(xs, ys, zs=zs) if precision is None: eps = sys.float_info.epsilon elif isinstance(precision, int): eps = 10.0**-precision else: eps = precision # If op rounds up, switch the sign of eps. if op(0.1) >= 1: eps = -eps f = lambda val: val + eps try: xs = list(map(f, xs)) ys = list(map(f, ys)) new_cols, new_rows = self._transform( xs, ys, zs, transform_direction=TransformDirection.reverse) if len(new_rows) == 1 and not AS_ARR: return (op(new_rows[0]), op(new_cols[0])) else: return ([op(r) for r in new_rows], [op(c) for c in new_cols]) except TypeError: raise TransformError("Invalid inputs")
def _ensure_arr_input(self, xs, ys, zs=None): """Ensure all input coordinates are mapped to array-like objects Raises ------ TransformError If input coordinates are not all of the same length """ if (isinstance(xs, Iterable) and not isinstance(ys, Iterable)) or ( isinstance(ys, Iterable) and not isinstance(xs, Iterable)): raise TransformError("Invalid inputs") if not isinstance(xs, Iterable) and not isinstance(ys, Iterable): xs = [xs] ys = [ys] if zs is None: zs = [0] * len(xs) elif not isinstance(zs, Iterable): zs = [zs] if len(set((len(xs), len(ys), len(zs)))) > 1: raise TransformError("Input coordinates must be of equal length") return xs, ys, zs
def rowcol(self, xs, ys, zs=None, op=math.floor, precision=None): """Get rows and cols coordinates given geographic coordinates. Parameters ---------- xs, ys : float or list of float Geographic coordinates zs : float or list of float, optional Height associated with coordinates. Primarily used for RPC based coordinate transformations. Ignored for affine based transformations. Default: 0. op : function, optional (default: math.floor) Function to convert fractional pixels to whole numbers (floor, ceiling, round) precision : int, optional (default: None) This parameter is unused, deprecated in rasterio 1.3.0, and will be removed in version 2.0.0. Raises ------ ValueError If input coordinates are not all equal length Returns ------- tuple of float or list of float. """ if precision is not None: warnings.warn( "The precision parameter is unused, deprecated, and will be removed in 2.0.0.", RasterioDeprecationWarning, ) AS_ARR = True if hasattr(xs, "__iter__") else False xs, ys, zs = self._ensure_arr_input(xs, ys, zs=zs) try: new_cols, new_rows = self._transform( xs, ys, zs, transform_direction=TransformDirection.reverse) if len(new_rows) == 1 and not AS_ARR: return (op(new_rows[0]), op(new_cols[0])) else: return ([op(r) for r in new_rows], [op(c) for c in new_cols]) except TypeError: raise TransformError("Invalid inputs")
def xy(self, rows, cols, zs=None, offset='center'): """ Returns geographic coordinates given dataset rows and cols coordinates Parameters ---------- rows, cols : int or list of int Image pixel coordinates zs : float or list of float, optional Height associated with coordinates. Primarily used for RPC based coordinate transformations. Ignored for affine based transformations. Default: 0. offset : str, optional Determines if the returned coordinates are for the center of the pixel or for a corner. Raises ------ ValueError If input coordinates are not all equal length Returns ------- tuple of float or list of float """ AS_ARR = True if hasattr(rows, "__iter__") else False rows, cols, zs = self._ensure_arr_input(rows, cols, zs=zs) if offset == 'center': coff, roff = (0.5, 0.5) elif offset == 'ul': coff, roff = (0, 0) elif offset == 'ur': coff, roff = (1, 0) elif offset == 'll': coff, roff = (0, 1) elif offset == 'lr': coff, roff = (1, 1) else: raise TransformError("Invalid offset") # shift input coordinates according to offset T = IDENTITY.translation(coff, roff) temp_rows = [] temp_cols = [] try: for pt in zip(cols, rows): y, x = T * pt temp_rows.append(y) temp_cols.append(x) new_ys, new_xs = self._transform( temp_rows, temp_cols, zs, transform_direction=TransformDirection.forward) if len(new_ys) == 1 and not AS_ARR: return (new_ys[0], new_xs[0]) else: return (new_ys, new_xs) except TypeError: raise TransformError("Invalid inputs")