def from_profile(profile: Union[Callable, Iterable[float]], z_range: Iterable[float]=np.linspace(-5, 0, 20), axis: Axis=Oz_axis, nphi: int=20, name=None): """Return a floating body using the axial symmetry. The shape of the body can be defined either with a function defining the profile as [f(z), 0, z] for z in z_range. Alternatively, the profile can be defined as a list of points. The number of vertices along the vertical direction is len(z_range) in the first case and profile.shape[0] in the second case. Parameters ---------- profile : function(float → float) or array(N, 3) define the shape of the body either as a function or a list of points. z_range: array(N), optional used only if the profile is defined as a function. axis : Axis symmetry axis nphi : int, optional number of vertical slices forming the body name : str, optional name of the generated body (optional) Returns ------- AxialSymmetricMesh the generated mesh """ if name is None: name = "axisymmetric_mesh" if callable(profile): z_range = np.asarray(z_range) x_values = [profile(z) for z in z_range] profile_array = np.stack([x_values, np.zeros(len(z_range)), z_range]).T else: profile_array = np.asarray(profile) assert len(profile_array.shape) == 2 assert profile_array.shape[1] == 3 n = profile_array.shape[0] angle = 2 * np.pi / nphi nodes_slice = np.concatenate([profile_array, axis.rotate_points(profile_array, angle)]) faces_slice = np.array([[i, i+n, i+n+1, i+1] for i in range(n-1)]) body_slice = Mesh(nodes_slice, faces_slice, name=f"slice_of_{name}") body_slice.merge_duplicates() body_slice.heal_triangles() return AxialSymmetricMesh(body_slice, axis=axis, nb_repetitions=nphi - 1, name=name)
def test_rotation_non_reference_axis(): axis = Axis(vector=(0, 0, 1), point=(1, 0, 0)) point = [[1.0, 0.0, 0.0]] rotated_point = axis.rotate_points(point, np.pi) assert np.allclose(rotated_point, point)