Source code for navis.transforms.affine
# This script is part of navis (http://www.github.com/navis-org/navis).
# Copyright (C) 2018 Philipp Schlegel
#
# This program 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.
#
# This program 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.
import copy
import numpy as np
from .base import BaseTransform
[docs]
class AffineTransform(BaseTransform):
"""Affine transformation of 3D spatial data.
Parameters
----------
matrix : (4, 4) np.ndarray
Affine matrix.
Examples
--------
A simple scaling transform
>>> from navis import transforms
>>> import numpy as np
>>> M = np.diag([1e3, 1e3, 1e3, 1])
>>> tr = transforms.affine.AffineTransform(M)
>>> points = np.array([[0, 0, 0], [1, 1, 1]])
>>> tr.xform(points)
array([[ 0., 0., 0.],
[1000., 1000., 1000.]])
"""
[docs]
def __init__(self, matrix: np.ndarray, direction: str = 'forward'):
"""Initialize transform."""
assert direction in ('forward', 'inverse')
self.matrix = matrix
if direction == 'inverse':
self.matrix = np.linalg.inv(self.matrix)
def __eq__(self, other: 'AffineTransform') -> bool:
"""Implements equality comparison."""
if isinstance(other, AffineTransform):
if np.all(self.matrix == other.matrix):
return True
return False
def __neg__(self):
"""Invert direction."""
x = self.copy()
# Invert affine matrix
x.matrix = np.linalg.inv(x.matrix)
return x
def copy(self) -> 'AffineTransform':
"""Return copy of transform."""
# Attributes not to copy
no_copy = []
# Generate new empty transform
x = self.__class__(None)
# Override with this neuron's data
x.__dict__.update({k: copy.copy(v) for k, v in self.__dict__.items() if k not in no_copy})
return x
def xform(self, points: np.ndarray, invert: bool = False) -> np.ndarray:
"""Apply transform to points.
Parameters
----------
points : np.ndarray
(N, 3) array of x/y/z locations.
invert : bool
If True, will invert the transform.
Returns
-------
pointsxf : np.ndarray
The transformed points.
"""
points = np.asarray(points)
if points.ndim != 2 and points.shape[1] != 3:
raise ValueError('`points` must be of shape (N, 3)')
# Add a fourth column to points
points_mat = np.ones((points.shape[0], 4))
points_mat[:, :3] = points
# Apply transform
if not invert:
mat = self.matrix
else:
mat = np.linalg.inv(self.matrix)
return np.dot(mat, points_mat.T).T[:, :3]