import math as m
from scanpointgenerator.compat import range_
from scanpointgenerator.core import Generator
from scanpointgenerator.core import Point
@Generator.register_subclass("scanpointgenerator:generator/LissajousGenerator:1.0")
[docs]class LissajousGenerator(Generator):
"""Generate the points of a Lissajous curve"""
def __init__(self, names, units, box, num_lobes, num_points=None):
"""
Args:
names (list(str)): The scannable names e.g. ["x", "y"]
units (str): The scannable units e.g. "mm"
box(dict): Dictionary of centre, width and height representing
box to fill with points
num_lobes(int): Number of x-direction lobes for curve; will
have num_lobes+1 y-direction lobes
num_points(int): The number of points to fill the Lissajous
curve. Default is 250 * num_lobes
"""
self.names = names
self.units = units
if len(self.names) != len(set(self.names)):
raise ValueError("Axis names cannot be duplicated; given %s" %
names)
num_lobes = int(num_lobes)
self.x_freq = num_lobes
self.y_freq = num_lobes + 1
self.x_max = box['width']/2
self.y_max = box['height']/2
self.centre = box['centre']
self.num = num_points
# Phase needs to be 0 for even lobes and pi/2 for odd lobes to start
# at centre for odd and at right edge for even
self.phase_diff = m.pi/2 * (num_lobes % 2)
if num_points is None:
self.num = num_lobes * 250
self.increment = 2*m.pi/self.num
self.position_units = {self.names[0]: units, self.names[1]: units}
self.index_dims = [self.num]
gen_name = "Lissajous"
for axis_name in self.names[::-1]:
gen_name = axis_name + "_" + gen_name
self.index_names = [gen_name]
self.axes = self.names # For GDA
def _calc(self, i):
"""Calculate the coordinate for a given index"""
x = self.centre[0] + \
self.x_max * m.sin(self.x_freq * i * self.increment +
self.phase_diff)
y = self.centre[1] + \
self.y_max * m.sin(self.y_freq * i * self.increment)
return x, y
def iterator(self):
for i in range_(self.num):
p = Point()
p.positions[self.names[0]], p.positions[self.names[1]] = self._calc(i)
p.lower[self.names[0]], p.lower[self.names[1]] = self._calc(i - 0.5)
p.upper[self.names[0]], p.upper[self.names[1]] = self._calc(i + 0.5)
p.indexes = [i]
yield p
[docs] def to_dict(self):
"""Convert object attributes into a dictionary"""
box = dict()
box['centre'] = self.centre
box['width'] = self.x_max * 2
box['height'] = self.y_max * 2
d = dict()
d['typeid'] = self.typeid
d['names'] = self.names
d['units'] = list(self.position_units.values())[0]
d['box'] = box
d['num_lobes'] = self.x_freq
d['num_points'] = self.num
return d
@classmethod
[docs] def from_dict(cls, d):
"""
Create a LissajousGenerator instance from a serialised dictionary
Args:
d(dict): Dictionary of attributes
Returns:
LissajousGenerator: New LissajousGenerator instance
"""
names = d['names']
units = d['units']
box = d['box']
num_lobes = d['num_lobes']
num_points = d['num_points']
return cls(names, units, box, num_lobes, num_points)