def visual_circle_and_ellipse(insert_x, insert_y, width, length, circle_centre): t = np.linspace(0, 2 * np.pi) circle = { "x": width / 2 * np.sin(t) + circle_centre[0], "y": width / 2 * np.cos(t) + circle_centre[1], } x_shift, y_shift, rotation_angle = visual_alignment_of_equivalent_ellipse( insert_x, insert_y, width, length, None) rotation_matrix = np.array([ [np.cos(rotation_angle), -np.sin(rotation_angle)], [np.sin(rotation_angle), np.cos(rotation_angle)], ]) ellipse = np.array([length / 2 * np.sin(t), width / 2 * np.cos(t)]).T rotated_ellipse = ellipse @ rotation_matrix translated_ellipse = rotated_ellipse + np.array([y_shift, x_shift]) ellipse = {"x": translated_ellipse[:, 1], "y": translated_ellipse[:, 0]} return circle, ellipse
def do_rotation(x_span, y_span, angle): """Generate a meshgrid and rotate it by `angle` degrees.""" radians = angle * np.pi / 180 rotation_matrix = np.array([[np.cos(radians), np.sin(radians)], [-np.sin(radians), np.cos(radians)]]) xx, yy = np.meshgrid(x_span, y_span, indexing="ij") return np.einsum("ji, mni -> jmn", rotation_matrix, np.dstack([xx, yy]))
def _multi_y_locations(self) -> List: """List of x-locations of the sampling profiles""" y = [] sin = np.sin(self._radians) # extract profile for each circle radii for radius in self._radii: y.append(sin * radius + self.center.y) return y
def calculate_coordinates_shell_2d(distance, distance_step_size): """Create points along the circumference of a circle. The spacing between points is not larger than the defined distance_step_size """ amount_to_check = np.ceil(2 * np.pi * distance / distance_step_size).astype(int) + 1 theta = np.linspace(0, 2 * np.pi, amount_to_check + 1)[:-1:] x_coords = distance * np.cos(theta) y_coords = distance * np.sin(theta) return (x_coords, y_coords)
def calculate_coordinates_shell_3d(distance, distance_step_size): """Create points along the surface of a sphere (a shell) where no gap between points is larger than the defined distance_step_size""" number_of_rows = np.ceil(np.pi * distance / distance_step_size).astype(int) + 1 elevation = np.linspace(0, np.pi, number_of_rows) row_radii = distance * np.sin(elevation) row_circumference = 2 * np.pi * row_radii amount_in_row = np.ceil(row_circumference / distance_step_size).astype(int) + 1 x_coords = [] y_coords = [] z_coords = [] for i, phi in enumerate(elevation): azimuth = np.linspace(0, 2 * np.pi, amount_in_row[i] + 1)[:-1:] x_coords.append(distance * np.sin(phi) * np.cos(azimuth)) y_coords.append(distance * np.sin(phi) * np.sin(azimuth)) z_coords.append(distance * np.cos(phi) * np.ones_like(azimuth)) return (np.hstack(x_coords), np.hstack(y_coords), np.hstack(z_coords))
def rotate_coords(x, y, theta): x_prime = x * np.cos(theta) + y * np.sin(theta) y_prime = -x * np.sin(theta) + y * np.cos(theta) return x_prime, y_prime
def stripes_artefact_func(x, attenuation=0.05, period=1.6): sin_result = np.sin(x * 2 * np.pi / period) return 1 - (sin_result + 1) / 2 * attenuation
def y_locations(self): """The x-locations of the profile values.""" if self._y_locations is None: return np.sin(self._radians) * self.radius + self.center.y else: return self._y_locations
def image_with_overlays( fig, ax, x, y, img, field_transform, bb_centre, field_centre, bb_diameter, edge_lengths, x_field_interp, y_field_interp, x_bb_interp, y_bb_interp, pixel_value_label, units="(mm)", ): rect_crosshair_dx = [ -edge_lengths[0] / 2, edge_lengths[0], -edge_lengths[0], edge_lengths[0], ] rect_crosshair_dy = [ -edge_lengths[1] / 2, edge_lengths[1], 0, -edge_lengths[1] ] rect_dx = [-edge_lengths[0] / 2, 0, edge_lengths[0], 0, -edge_lengths[0]] rect_dy = [-edge_lengths[1] / 2, edge_lengths[1], 0, -edge_lengths[1], 0] c = ax.contourf(x, y, img, 100) fig.colorbar(c, ax=ax, label=pixel_value_label) ax.plot(*draw_by_diff(rect_dx, rect_dy, field_transform), "k", lw=3) ax.plot(*draw_by_diff(rect_crosshair_dx, rect_crosshair_dy, field_transform), "k", lw=1) ax.plot(x_field_interp[0], x_field_interp[1], "k", lw=0.5, alpha=0.3) ax.plot(y_field_interp[0], y_field_interp[1], "k", lw=0.5, alpha=0.3) if bb_centre is not None: bb_radius = bb_diameter / 2 bb_crosshair = np.array([-bb_radius, bb_radius]) t = np.linspace(0, 2 * np.pi) circle_x_origin = bb_diameter / 2 * np.sin(t) circle_y_origin = bb_diameter / 2 * np.cos(t) circle_x = circle_x_origin + bb_centre[0] circle_y = circle_y_origin + bb_centre[1] ax.plot([bb_centre[0]] * 2, bb_crosshair + bb_centre[1], "k", lw=1) ax.plot(bb_crosshair + bb_centre[0], [bb_centre[1]] * 2, "k", lw=1) ax.plot(circle_x, circle_y, "k", lw=3) ax.plot(x_bb_interp[0], x_bb_interp[1], "k", lw=0.5, alpha=0.3) ax.plot(y_bb_interp[0], y_bb_interp[1], "k", lw=0.5, alpha=0.3) ax.plot( [field_centre[0], bb_centre[0]], [field_centre[1], bb_centre[1]], c="C3", lw=3, ) ax.axis("equal") long_edge = np.sqrt(np.sum((np.array(edge_lengths))**2)) long_edge_fraction = long_edge * 0.6 ax.set_xlim([ field_centre[0] - long_edge_fraction, field_centre[0] + long_edge_fraction ]) ax.set_ylim([ field_centre[1] - long_edge_fraction, field_centre[1] + long_edge_fraction ]) ax.set_xlabel(f"iView panel absolute x-pos {units}") ax.set_ylabel(f"iView panel absolute y-pos {units}")