Source code for openlifu.bf.focal_patterns.wheel
from __future__ import annotations
from dataclasses import dataclass
from typing import Annotated
import numpy as np
from openlifu.bf.focal_patterns import FocalPattern
from openlifu.geo import Point
from openlifu.util.annotations import OpenLIFUFieldData
[docs]
@dataclass
class Wheel(FocalPattern):
"""
Class for representing a wheel pattern
"""
center: Annotated[bool, OpenLIFUFieldData("Include center point?", "Whether to include the center for the wheel pattern")] = True
"""Whether to include the center for the wheel pattern"""
num_spokes: Annotated[int, OpenLIFUFieldData("Number of spokes", "Number of spokes in the wheel pattern")] = 4
"""Number of spokes in the wheel pattern"""
spoke_radius: Annotated[float, OpenLIFUFieldData("Spoke radius", "Radius of the spokes in the wheel pattern")] = 1.0 # mm
"""Radius of the spokes in the wheel pattern"""
distance_units: Annotated[str, OpenLIFUFieldData("Units", "Units of the wheel pattern parameters")] = "mm"
"""Units of the wheel pattern parameters"""
[docs]
def get_targets(self, target: Point):
"""
Get the targets of the focal pattern
:param target: Target point of the focal pattern
:returns: List of target points
"""
if self.center:
targets = [target.copy()]
targets[0].id = f"{target.id}_center"
targets[0].id = f"{target.id} (Center)"
else:
targets = []
m = target.get_matrix(center_on_point=True)
for i in range(self.num_spokes):
theta = 2*np.pi*i/self.num_spokes
local_position = self.spoke_radius * np.array([np.cos(theta), np.sin(theta), 0.0])
position = np.dot(m, np.append(local_position, 1.0))[:3]
spoke = Point(id=f"{target.id}_{np.rad2deg(theta):.0f}deg",
name=f"{target.name} ({np.rad2deg(theta):.0f}°)",
position=position,
units=self.distance_units,
radius=target.radius)
targets.append(spoke)
return targets
[docs]
def num_foci(self) -> int:
"""
Get the number of foci in the focal pattern
:returns: Number of foci
"""
return int(self.center) + self.num_spokes