def __init__( self, slits: int, slit_edges: np.ndarray, radius: float, slit_height: float, angle_units: str, slit_height_units: str, radius_units: str, ): """ Class for storing the chopper input given by the user. :param slits: The number of slits in the disk chopper. :param slit_edges: The list of slit edge angles in the disk chopper. :param radius: The radius of the slit chopper. :param slit_height: The slit height. :param angle_units: The units of the slit edges. :param slit_height_units: The units for the slit length. :param radius_units: The units for the radius. """ self._slits = slits self._radius = radius self._slit_height = slit_height # Convert the angles to radians and make sure they are all less then two pi slit_edges_factor = calculate_unit_conversion_factor( angle_units, RADIANS) self._slit_edges = [(edge * slit_edges_factor) % TWO_PI for edge in slit_edges] self._slit_height *= calculate_unit_conversion_factor( slit_height_units, METRES) self._radius *= calculate_unit_conversion_factor(radius_units, METRES)
def _evaluate_ui_scale_factor(self, units): try: if self.transform_type == TransformationType.TRANSLATION: self._ui_scale_factor = calculate_unit_conversion_factor(units, METRES) elif self.transform_type == TransformationType.ROTATION: self._ui_scale_factor = calculate_unit_conversion_factor(units, DEGREES) except Exception: pass
def _create_transformation_vectors_for_pixel_offsets( self, ) -> Optional[List[QVector3D]]: """ Construct a transformation (as a QVector3D) for each pixel offset """ try: units = self.get_field_attribute(X_PIXEL_OFFSET, CommonAttrs.UNITS) unit_conversion_factor = calculate_unit_conversion_factor( units, METRES) x_offsets = self.get_field_value( X_PIXEL_OFFSET) * unit_conversion_factor y_offsets = self.get_field_value( Y_PIXEL_OFFSET) * unit_conversion_factor except AttributeError: logging.info( "In pixel_shape_component expected to find x_pixel_offset and y_pixel_offset datasets" ) return None try: z_offsets = self.get_field_value(Z_PIXEL_OFFSET) except AttributeError: z_offsets = np.zeros_like(x_offsets) if not isinstance(x_offsets, list): x_offsets = x_offsets.flatten() if not isinstance(y_offsets, list): y_offsets = y_offsets.flatten() if not isinstance(z_offsets, list): z_offsets = z_offsets.flatten() # offsets datasets can be 2D to match dimensionality of detector, so flatten to 1D return [ QVector3D(x, y, z) for x, y, z in zip(x_offsets, y_offsets, z_offsets) ]
def load_geometry_from_file_object( file: StringIO, extension: str, units: str, geometry: OFFGeometry = OFFGeometryNoNexus(), ) -> OFFGeometry: """ Loads geometry from a file object into an OFFGeometry instance Supported file types are OFF and STL. :param file: The file object to load the geometry from. :param units: A unit of length in the form of a string. Used to determine the multiplication factor. :param geometry: The optional OFFGeometry to load the geometry data into. If not provided, a new instance will be returned. :return: An OFFGeometry instance containing that file's geometry, or an empty instance if filename's extension is unsupported. """ mult_factor = calculate_unit_conversion_factor(units, METRES) if extension == ".off": _load_off_geometry(file, mult_factor, geometry) elif extension == ".stl": _load_stl_geometry(file, mult_factor, geometry) else: geometry.faces = [] geometry.vertices = [] logging.error("geometry file extension not supported") return geometry
def test_unit_conversion_factor(): # List of units and their expected value in metres units = [("cm", 0.01), ("km", 1000), ("m", 1.0), ("inch", 0.0254), ("foot", 0.3048)] # Check that the unit conversion factor can correctly find the unit in terms of meters for unit in units: assert approx(calculate_unit_conversion_factor(unit[0], METRES)) == unit[1]
def test_if_VALID_unit_is_entered_in_ROTATION_then_ui_scale_factor_is_evaluated_correctly(): test_type = "rotation" transformation = create_transform(type=test_type, units="deg") assert transformation._ui_scale_factor == 1 transformation.units = "radian" assert transformation._ui_scale_factor == calculate_unit_conversion_factor( RADIANS, DEGREES )
def off_geometry(self) -> OFFGeometry: steps: int = 10 unit_conversion_factor = calculate_unit_conversion_factor( self.units, METRES) # A list of vertices describing the circle at the bottom of the cylinder bottom_circle = [ QVector3D(sin(2 * pi * i / steps), cos(2 * pi * i / steps), 0) * self.radius for i in range(steps) ] # The top of the cylinder is the bottom shifted upwards top_circle = [ vector + QVector3D(0, 0, self.height) for vector in bottom_circle ] # The true cylinder are all vertices from the unit cylinder multiplied by the conversion factor vertices = [ vector * unit_conversion_factor for vector in bottom_circle + top_circle ] # rotate each vertex to produce the desired cylinder mesh rotate_matrix = self._rotation_matrix() vertices = [vector * rotate_matrix for vector in vertices] def vertex_above(vertex): """ Returns the index of the vertex above this one in the cylinder. """ return vertex + steps def next_vertex(vertex): """ Returns the next vertex around in the top or bottom circle of the cylinder. """ return (vertex + 1) % steps # Rectangular faces joining the top and bottom rectangle_faces = [[ i, vertex_above(i), vertex_above(next_vertex(i)), next_vertex(i) ] for i in range(steps)] # Step sided shapes describing the top and bottom # The bottom uses steps of -1 to preserve winding order top_bottom_faces = [ [i for i in range(steps)], [i for i in range((2 * steps) - 1, steps - 1, -1)], ] return OFFGeometryNoNexus(vertices=vertices, faces=rectangle_faces + top_bottom_faces)