Source code for fibomat.shapes.rasterizedpoints

"""Provides the :class:`RasterizedPoints` class."""
from __future__ import annotations
from typing import List, Optional

import numpy as np

from fibomat.linalg import Vector, VectorLike, BoundingBox
from fibomat.shapes import Shape


[docs]class RasterizedPoints(Shape): """Class represents pre-rasterized points."""
[docs] def __init__(self, dwell_points: np.ndarray, is_closed: bool, description: Optional[str] = None): """ Args: dwell_points (np.ndarray): dim must be 2 with shape = (-1, 3). First to components are coordinates and third a dwell time multiplicand. is_closed (bool): if True, shape is considered as closed. description (str, optional): description Raises: ValueError: Raised if dimension or shape of dwell points is wrong """ super().__init__(description) if dwell_points.ndim != 2: raise ValueError('dwell_points mus have dimension 2.') if dwell_points.shape[1] != 3: raise ValueError('dwell_points must have shape (N, 3)') self._dwell_points = dwell_points self._is_closed = bool(is_closed)
[docs] @classmethod def merged(cls, other_raster_points: List[RasterizedPoints]) -> RasterizedPoints: """Create merged :class:`RasterizedPoints` class from list of :class:`RasterizedPoints`. Args: other_raster_points: points to be merged. Returns: RasterizedPoints """ total_points = 0 for raster_points in other_raster_points: total_points += raster_points.n_points dwell_points = np.empty(shape=(total_points, 3), dtype=float) i_offset = 0 for raster_points in other_raster_points: dwell_points[i_offset:i_offset+raster_points.n_points] = raster_points.dwell_points i_offset += raster_points.n_points return cls(dwell_points, False)
@property def positions(self): """Coordinates of dwell points. Access: get Returns: np.ndarray """ view = self._dwell_points[:, :2] view.flags.writeable = False return view @property def weights(self): """Dwell time multiplicator of dwell points. Access: get Returns: np.ndarray """ view = self._dwell_points[:, 2] view.flags.writeable = False return view @property def dwell_points(self): """Dwell points. Access: get Returns: np.ndarray """ view = self._dwell_points[:] view.flags.writeable = False return view @property def n_points(self) -> int: """Number of dwell points. Access: get Returns: int """ return len(self._dwell_points) @property def is_closed(self) -> bool: return self._is_closed def __repr__(self) -> str: return 'RasterizedPoints(...)' @property def bounding_box(self) -> BoundingBox: return BoundingBox.from_points(self.positions) @property def center(self) -> Vector: return Vector(np.mean(self.positions, axis=1)) def _impl_translate(self, trans_vec: VectorLike) -> None: self._dwell_points[:, :2] += trans_vec def _impl_rotate(self, theta: float) -> None: # pylint: disable=invalid-name theta = float(theta) m = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) self._dwell_points[:, :2] = self._dwell_points[:, 2] @ m.T def _impl_scale(self, fac: float) -> None: self._dwell_points[:, :2] *= float(fac) def _impl_mirror(self, mirror_axis: VectorLike) -> None: # pylint: disable=invalid-name mirror_axis = Vector(mirror_axis) lx, ly = mirror_axis mirror_matrix = np.array([[lx*lx - ly*ly, 2*lx*ly], [2*lx*ly, ly*ly - lx*lx]]) / mirror_axis.length self._dwell_points[:, :2] = mirror_matrix.dot(self._dwell_points[:, :2].T)
[docs] def repeats_applied(self, repeats: int) -> RasterizedPoints: """Return :class:`RasterizedPoints` with dwel points repeated `repeats` times. Args: repeats: number of repeats. Returns: RasterizedPoints """ if repeats != 1: # TODO: check and replace # np.tile(self._dwell_points, (repeats, 1)) return RasterizedPoints(np.concatenate([self._dwell_points]*repeats), self._is_closed) return self