Source code for scanpointgenerator.generators.spiralgenerator

import math as m

from scanpointgenerator.compat import range_
from scanpointgenerator.core import Generator
from scanpointgenerator.core import Point


@Generator.register_subclass("scanpointgenerator:generator/SpiralGenerator:1.0")
[docs]class SpiralGenerator(Generator): """Generate the points of an Archimedean spiral""" def __init__(self, names, units, centre, radius, scale=1.0, alternate_direction=False): """ Args: names (list(str)): The scannable names e.g. ["x", "y"] units (str): The scannable units e.g. "mm" centre(list): List of two coordinates of centre point of spiral radius(float): Radius of spiral scale(float): Rate at which spiral expands; higher scale gives fewer points for same radius alternate_direction(bool): Specifier to reverse direction if generator is nested """ self.names = names self.units = units self.centre = centre self.radius = radius self.scale = scale self.alternate_direction = alternate_direction if len(self.names) != len(set(self.names)): raise ValueError("Axis names cannot be duplicated; given %s" % names) self.alpha = m.sqrt(4 * m.pi) # Theta scale factor self.beta = scale / (2 * m.pi) # Radius scale factor self.num = self._end_point(self.radius) + 1 self.position_units = {names[0]: units, names[1]: units} self.index_dims = [self._end_point(self.radius)] gen_name = "Spiral" 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""" theta = self.alpha * m.sqrt(i) radius = self.beta * theta x = self.centre[0] + radius * m.sin(theta) y = self.centre[1] + radius * m.cos(theta) return x, y def _end_point(self, radius): """Calculate the index of the final point contained by circle""" return int((radius / (self.alpha * self.beta)) ** 2) def iterator(self): for i in range_(0, self._end_point(self.radius) + 1): p = Point() p.indexes = [i] i += 0.5 # Offset so lower bound of first point is not less than 0 p.positions[self.names[0]], p.positions[self.names[1]] = self._calc(i) p.upper[self.names[0]], p.upper[self.names[1]] = self._calc(i + 0.5) p.lower[self.names[0]], p.lower[self.names[1]] = self._calc(i - 0.5) yield p
[docs] def to_dict(self): """Convert object attributes into a dictionary""" d = dict() d['typeid'] = self.typeid d['names'] = self.names d['units'] = list(self.position_units.values())[0] d['centre'] = self.centre d['radius'] = self.radius d['scale'] = self.scale d['alternate_direction'] = self.alternate_direction return d
@classmethod
[docs] def from_dict(cls, d): """ Create a SpiralGenerator instance from a serialised dictionary Args: d(dict): Dictionary of attributes Returns: SpiralGenerator: New SpiralGenerator instance """ names = d['names'] units = d['units'] centre = d['centre'] radius = d['radius'] scale = d['scale'] alternate_direction = d['alternate_direction'] return cls(names, units, centre, radius, scale, alternate_direction)