# BEGIN OF LICENSE NOTE
# This file is part of Pyoints.
# Copyright (c) 2018, Sebastian Lamprecht, Trier University,
# lamprecht@uni-trier.de
#
# Pyoints is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyoints is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Pyoints. If not, see <https://www.gnu.org/licenses/>.
# END OF LICENSE NOTE
"""Conversion of coordinates to cell indices and reverse by applying
transformations.
"""
import numpy as np
from .. import (
assertion,
transformation,
registration,
Extent,
)
from ..misc import print_rounded
[docs]def keys_to_indices(keys, shape):
"""Converts matrix keys to indices.
Parameters
----------
keys : array_like(int)
Keys of matrix.
shape : array_like(int, shape=(k))
Shape of the input matrix.
Returns
-------
np.ndarray(int)
Desired indices vector associated with the requested keys.
"""
w = np.concatenate((
np.array([np.product(shape[i:]) for i in range(len(shape))])[1:],
[1]
))
return (keys * w).sum(1)
[docs]def indices_to_keys(indices, shape):
"""Converts indices vector to keys of a matrix.
Parameters
----------
indices : array_like(int, shape=(n))
Index vector to convert to matrix keys. Each element `i` specifies the
`i`-th`element in the matrix.
shape : array_like(int, shape=(k))
Shape of output matrix.
Returns
-------
np.ndarray(int, shape=shape)
Desired matrix keys associated with requested indices.
"""
indices = assertion.ensure_numvector(indices)
shape = assertion.ensure_numvector(shape)
keys = []
w = np.concatenate((
np.array([np.product(shape[i:]) for i in range(len(shape))])[1:],
[1]
))
for d in w:
keys.append(indices / d)
indices = indices % d
keys = np.array(keys, dtype=int).T
return keys
[docs]def coords_to_keys(T, coords):
"""Transforms coordinates to matrix indices.
Parameters
----------
T : array_like(Number, shape=(k+1,k+1))
A linear transformation matrix to transform the coordinates.
The translation represents the origin, the rotation represents the
orientation and the scale represents the pixel size of a raster.
coords : array_like(Number, shape=(n, k))
Coordinates with at least `k` dimensions to convert to indices.
Returns
-------
keys : np.ndarray(int, shape=(n, k))
Indices of the coordinates within the grid.
See Also
--------
keys_to_coords, coords_to_coords
"""
coords = assertion.ensure_numarray(coords)
dim = coords.shape[-1]
T = transformation.LocalSystem(assertion.ensure_tmatrix(T, dim=dim))
s = np.product(coords.shape) // dim
flat_coords = coords.reshape((s, dim))
values = T.to_global(flat_coords)
keys = values.astype(int)[:, ::-1]
return keys.reshape(coords.shape)
[docs]def keys_to_coords(T, keys):
"""Converts indices of raster cells to coordinates.
Parameters
----------
T : array_like(Number, shape=(k+1,k+1))
The transformation matrix of a `k` dimensional raster.
keys : array_like(int, shape=(n, k))
Indices of `n` raster cells.
Returns
-------
coords : array_like(Number, shape=(n, k))
Desired coordinates of the raster cells.
See Also
--------
coords_to_keys, coords_to_coords
"""
keys = assertion.ensure_numarray(keys)
dim = keys.shape[-1]
T = transformation.LocalSystem(assertion.ensure_tmatrix(T, dim=dim))
s = np.product(keys.shape) // dim
flat_keys = keys.reshape((s, dim))[:, ::-1] + 0.5
coords = T.to_local(flat_keys).astype(float)
return coords.reshape(keys.shape)
[docs]def coords_to_coords(T, coords):
"""Aligns coordinates with a raster grid.
Parameters
----------
T : array_like(Number, shape=(k+1, k+1))
The transformation matrix of a `k` dimensional raster.
coords : array_like(Number, shape=(n, k))
Coordinates to align with a raster grid.
Returns
-------
coords : array_like(Number, shape=(n, k))
Desired coordinates aligned with the grid.
See Also
--------
coords_to_keys, keys_to_coords
"""
return keys_to_coords(T, coords_to_keys(T, coords))
[docs]def extentinfo(T, extent):
"""Receives information on a raster subset with given boundaries.
Parameters
----------
T : array_like(Number, shape=(k+1,k+1))
The transformation matrix of a `k` dimensional grid.
extent : array_like(Number, shape=(2 * k))
Desired extent.
Returns
-------
T : array_like(Number, shape=(k+1,k+1))
Extent of the original raster.
origin_key : array_like(int, shape=(k))
Key or index of the origin of the new transformation matrix.
shape : np.array(int, shape=(k))
Shape of the grid subset.
Examples
--------
>>> T = transformation.matrix(t=[100, 200], s=[2, -2])
>>> ext = Extent([150, 250, 200, 300])
>>> M, min_corner_key, shape = extentinfo(T, ext)
>>> print_rounded(M)
[[ 2. 0. 150.]
[ 0. -2. 300.]
[ 0. 0. 1.]]
>>> print_rounded(min_corner_key)
[-50 25]
>>> print_rounded(shape)
[26 26]
"""
# ensure extent
extent = Extent(extent)
T = assertion.ensure_tmatrix(T)
dim = len(extent) // 2
if not T.shape[0] - 1 == dim:
raise ValueError('dimensions do not match')
corner_keys = coords_to_keys(T, extent.corners)
shape = np.ptp(corner_keys, axis=0) + 1
# Minimum corner
idx = np.argmin(corner_keys, axis=0)
origin_key = corner_keys[idx, range(dim)]
min_corner = keys_to_coords(T, [origin_key - 0.5])[0, :]
# define transformation
t = np.copy(T)
t[:-1, dim] = min_corner
return t, origin_key, shape