def arc_between_two_points(coordinate_system, point1, point2, radius=1, right=True): global_point1 = coordinate_system.to_parent(point1) global_point2 = coordinate_system.to_parent(point2) direction = point2 - point1 distance = np.sqrt(np.dot(direction, direction)) arc_coordinate_system = Cartesian(basis=np.copy(coordinate_system.basis), origin=np.copy(global_point1), name='Arc coordinate_system') r_theta_phi = transforms.cartesian_to_spherical(direction) arc_coordinate_system.rotate_axis_angle([0, 0, 1], r_theta_phi[2]) arc_coordinate_system.rotate_axis_angle([0, 1, 0], r_theta_phi[1] + np.pi/2) x_offset = -distance / 2 y_offset = np.sqrt(radius**2 - x_offset**2) if right: y_offset *= -1 arc_coordinate_system.origin = arc_coordinate_system.to_parent([x_offset, y_offset, 0]) local_point1 = arc_coordinate_system.to_local(global_point1) local_point2 = arc_coordinate_system.to_local(global_point2) start = transforms.cartesian_to_spherical(local_point1)[2] stop = transforms.cartesian_to_spherical(local_point2)[2] if not right: start = 2 * np.pi - start stop = 2 * np.pi - stop path = Arc(coordinate_system=arc_coordinate_system, a=radius, b=radius, start=start, stop=stop, right=right) return path
def helix_between_two_points(coordinate_system, point1, point2, radius=1, loops=1, right=True): direction = point2 - point1 distance = np.sqrt(np.dot(direction, direction)) origin = coordinate_system.to_parent(point1) helix_coordinate_system = Cartesian(basis=np.copy(coordinate_system.basis), origin=np.copy(origin), name='Helix coordinate system') r_theta_phi = transforms.cartesian_to_spherical(direction) helix_coordinate_system.rotate_axis_angle([0, 0, 1], r_theta_phi[2]) helix_coordinate_system.rotate_axis_angle([0, 1, 0], r_theta_phi[1]) pitch = distance / int(loops) name = 'Right Helix' if right else 'Left Helix' path = Helix(name=name, coordinate_system=helix_coordinate_system, radius=radius, pitch=pitch, start=0, stop=np.pi * 2 * int(loops), right=right) return path
def test_rotation_axis_angle(self): other_coordinate_system = Cartesian() order = 3 axis = [1, 1, 2] steps = 10**order # per turn step = 2 * np.pi / steps for k in range(steps): other_coordinate_system.rotate_axis_angle(axis, step) self.assertEqual(self.coordinate_system, other_coordinate_system) np.testing.assert_allclose(self.coordinate_system.basis, other_coordinate_system.basis, atol=np.finfo(float).eps*steps) axis = [1, 0, 0] self.coordinate_system.rotate_axis_angle(axis, np.pi) np.testing.assert_allclose(self.coordinate_system.basis, np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]), atol=np.finfo(float).eps) self.coordinate_system.rotate_axis_angle(axis, np.pi) np.testing.assert_allclose(self.coordinate_system.basis, np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), atol=2*np.finfo(float).eps)
def __init__(self, name, coordinate_system=None): if coordinate_system is None: self.coordinate_system = Cartesian() elif isinstance(coordinate_system, Cartesian): self.coordinate_system = coordinate_system else: raise ValueError('coordinates system must be instance of Cartesian class') self.name = str(name) self.parent = None self.elements = {} self.points = None
def test_to_parent_to_local(self): origin = (np.random.random(3) - 0.5) * 100 other_coordinate_system = Cartesian(origin=origin) axis = (np.random.random(3) - 0.5) * 100 angle = (np.random.random() - 0.5) * 100 other_coordinate_system.rotate_axis_angle(axis, angle) point_global = (np.random.random(3) - 0.5) * 100 point_local = other_coordinate_system.to_local(point_global) point_global2 = other_coordinate_system.to_parent(point_local) np.testing.assert_allclose(point_global2, point_global, atol=np.finfo(float).eps) point_local = (np.random.random(3) - 0.5) * 100 point_global = other_coordinate_system.to_parent(point_local) point_local_2 = other_coordinate_system.to_local(point_global) np.testing.assert_allclose(point_local_2, point_local, atol=np.finfo(float).eps)
from matplotlib import pyplot as plt use_mpl = True except ImportError: use_mpl = True from Space.Coordinates import Cartesian def error(cs_1, cs_2): delta = cs_1.basis - cs_2.basis return np.sqrt(np.sum(delta ** 2)) # Create cartesian coordinate system # if you don't pass arguments the basis coincide with 'Absolute' (mayavi) coordinate system cs_1 = Cartesian(origin=np.array([0, 0, 0]), euler_angles_convention='Bunge') cs_2 = Cartesian(origin=np.array([0, 0, 0]), euler_angles_convention='Bunge') print(cs_1) turns = 10 axis = np.array([1, 1, 1]) steps = 1 # per turn max_steps_order = 4 errors = [] for order in range(max_steps_order + 1): steps = 10**order # per turn print("Processing %g steps per turn" % steps) step = 2 * np.pi / steps print(" Angle increment is %g rad (%g deg)" % (step, np.rad2deg(step))) laps_errors = []
class Space(object): def __init__(self, name, coordinate_system=None): if coordinate_system is None: self.coordinate_system = Cartesian() elif isinstance(coordinate_system, Cartesian): self.coordinate_system = coordinate_system else: raise ValueError('coordinates system must be instance of Cartesian class') self.name = str(name) self.parent = None self.elements = {} self.points = None def __str__(self): description = 'Space: %s\n' % self.name description += str(self.coordinate_system) return description def to_global_coordinate_system(self, xyz): """ convert local points coordinates xyz to global coordinate system coordinates :param xyz: array of points shaped Nx3 :return: array of points in global coordinates system """ parent_xyz = self.coordinate_system.to_parent(xyz) if self.parent is None: return parent_xyz else: return self.parent.to_global_coordinate_system(parent_xyz) def basis_in_global_coordinate_system(self): """ returns local coordinate system basis in global coordinate system as Cartesian class object :return: local Cartesian coordinate system in global coordinate system """ origin = np.copy(self.coordinate_system.origin) basis = np.copy(self.coordinate_system.basis) if self.parent is not None: basis = self.parent.to_global_coordinate_system(basis + origin) origin = self.parent.to_global_coordinate_system(origin) basis = basis - origin name = self.coordinate_system.name labels = self.coordinate_system.labels coordinate_system = Cartesian(basis=basis, origin=origin, name=name, labels=labels) return coordinate_system def to_local_coordinate_system(self, xyz): """ convert global points coordinates xyz to local coordinate system coordinates :param xyz: array of points shaped Nx3 :return: array of points in local coordinates system """ basis_global = self.basis_in_global_coordinate_system() return basis_global.to_local(xyz) def add_element(self, element): if isinstance(element, Space): if element == self: raise ValueError('Space can not be its own subspace') else: if element.parent is None: element_name = element.name name_counter = 1 name_format = ' %d' while element_name in self.elements.keys(): element_name = element.name + name_format % name_counter name_counter += 1 element.name = element_name self.elements[element.name] = element element.parent = self elif element.parent == self: print('Space ' + element.name + 'is already a subspace of ' + self.name) else: raise ValueError(element.name + ' is subspace of another space: ' + element.parent.name + '. Please delete first.') else: raise ValueError('Only another space could be included as a subspace') def remove_element(self, element): if isinstance(element, Space): if element.parent == self: for key in self.elements.keys(): if self.elements[key] == element: del self.elements[key] element.parent = None else: print(element.name + ' is not a subspace of ' + self.name) else: raise ValueError('Only another space could be detached') def detach_from_parent(self): if self.parent is not None: self.parent.remove_element(self) def print_tree(self, level=0): print('-' * level + ' ' * (level > 0) + self.name) for key in self.elements.keys(): self.elements[key].print_tree(level=level+1)
from __future__ import division, print_function import numpy as np from mayavi import mlab from Space.Coordinates import Cartesian from Space.Curve.Parametric import Helix from Space.Pathfinder import line_between_two_points, helix_between_two_points, arc_between_two_points import Space_visualization as Visual coordinate_system = Cartesian() coordinate_system.rotate_axis_angle(np.ones(3), np.deg2rad(45)) fig = mlab.figure('CS demo', bgcolor=(0, 0, 0)) Visual.draw_coordinate_system_axes(fig, coordinate_system) right_helix = Helix(name='Right Helix', coordinate_system=coordinate_system, radius=2, pitch=0.5, start=0, stop=np.pi * 4, right=True) left_helix = Helix(name='Left Helix', coordinate_system=coordinate_system, radius=2, pitch=0.5, start=0, stop=np.pi * 2, right=False) print('Helix length:', left_helix.length()) right_helix_view = Visual.CurveView(fig=fig, curve=right_helix) right_helix_view.draw() left_helix_view = Visual.CurveView(fig=fig, curve=left_helix) left_helix_view.draw() point1 = np.array([1, 1, 0]) point2 = np.array([2, 2, 0]) points = np.vstack((coordinate_system.to_parent(point1), coordinate_system.to_parent(point2)))
def setUp(self): self.coordinate_system = Cartesian()
class TestCoordinates(unittest.TestCase): def setUp(self): self.coordinate_system = Cartesian() def test_equality(self): other_coordinate_system = Cartesian() self.assertEqual(self.coordinate_system, other_coordinate_system) other_coordinate_system.origin = [1, 0, 0] self.assertNotEqual(self.coordinate_system, other_coordinate_system) def test_rotation_axis_angle(self): other_coordinate_system = Cartesian() order = 3 axis = [1, 1, 2] steps = 10**order # per turn step = 2 * np.pi / steps for k in range(steps): other_coordinate_system.rotate_axis_angle(axis, step) self.assertEqual(self.coordinate_system, other_coordinate_system) np.testing.assert_allclose(self.coordinate_system.basis, other_coordinate_system.basis, atol=np.finfo(float).eps*steps) axis = [1, 0, 0] self.coordinate_system.rotate_axis_angle(axis, np.pi) np.testing.assert_allclose(self.coordinate_system.basis, np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]), atol=np.finfo(float).eps) self.coordinate_system.rotate_axis_angle(axis, np.pi) np.testing.assert_allclose(self.coordinate_system.basis, np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), atol=2*np.finfo(float).eps) def test_euler_angles(self): self.coordinate_system.euler_angles_convention = 'Bunge' axis = [1, 0, 0] self.coordinate_system.rotate_axis_angle(axis, np.pi) np.testing.assert_allclose(self.coordinate_system.euler_angles, np.array([0, np.pi, 0]), atol=np.finfo(float).eps) self.coordinate_system.rotate_axis_angle(axis, np.pi) np.testing.assert_allclose(self.coordinate_system.euler_angles, np.array([0, 0, 0]), atol=np.finfo(float).eps * 2) self.coordinate_system.rotate_axis_angle(axis, np.pi / 2) #np.testing.assert_allclose(self.coordinate_system.euler_angles, # np.array([0, np.pi / 2, 0]), atol=np.finfo(float).eps * 2) self.coordinate_system.rotate_axis_angle(axis, np.pi / 2) np.testing.assert_allclose(self.coordinate_system.euler_angles, np.array([0, np.pi, 0]), atol=np.finfo(float).eps) self.coordinate_system.rotate_axis_angle(axis, np.pi / 2) #np.testing.assert_allclose(self.coordinate_system.euler_angles, # np.array([np.pi, np.pi / 2, np.pi]), atol=np.finfo(float).eps) self.coordinate_system.rotate_axis_angle(axis, np.pi / 2) np.testing.assert_allclose(self.coordinate_system.euler_angles, np.array([0, 0, 0]), atol=np.finfo(float).eps * 4) def test_to_parent_to_local(self): origin = (np.random.random(3) - 0.5) * 100 other_coordinate_system = Cartesian(origin=origin) axis = (np.random.random(3) - 0.5) * 100 angle = (np.random.random() - 0.5) * 100 other_coordinate_system.rotate_axis_angle(axis, angle) point_global = (np.random.random(3) - 0.5) * 100 point_local = other_coordinate_system.to_local(point_global) point_global2 = other_coordinate_system.to_parent(point_local) np.testing.assert_allclose(point_global2, point_global, atol=np.finfo(float).eps) point_local = (np.random.random(3) - 0.5) * 100 point_global = other_coordinate_system.to_parent(point_local) point_local_2 = other_coordinate_system.to_local(point_global) np.testing.assert_allclose(point_local_2, point_local, atol=np.finfo(float).eps)
def test_equality(self): other_coordinate_system = Cartesian() self.assertEqual(self.coordinate_system, other_coordinate_system) other_coordinate_system.origin = [1, 0, 0] self.assertNotEqual(self.coordinate_system, other_coordinate_system)
import numpy as np from mayavi import mlab from Space import Space from Space.Figure.Sphere import * from Space.Figure.Cylinder import CylindricalWedge, Cylinder from Space.Figure.Cone import ConicalWedge from Space.Figure.Torus import ToricWedge from Space.Figure.Cube import Parallelepiped, ParallelepipedTriclinic, Cuboid, Cube from Space.Curve.Parametric import Arc from Space.Coordinates import Cartesian import Space_visualization as Visual fig = mlab.figure('CS demo', bgcolor=(0.5, 0.5, 0.5)) # Create the mayavi figure joint_disc_cs = Cartesian() joint_disc_cs.euler_angles = (0, np.pi/2, 0) joint_disc = Cylinder(name='Moon', coordinate_system=joint_disc_cs, r_inner=0.0, r_outer=1.5, z=[-1.0, 1.0]) rod = Cylinder(name='Moon', coordinate_system=Cartesian(origin=[0.0, 0.0, 0.0]), r_inner=0.3, r_outer=0.5, z=[0.0, 4]) box = ParallelepipedTriclinic(name='Parallelepiped', a=1, b=1, c=1, alpha=np.pi/4, beta=np.pi/4, gamma=np.pi/4) #wedge = SphericalWedge(r_inner=5, r_outer=7, phi=2*np.pi*0.7, theta=[np.pi/4*0, np.pi/3]) wedge = ConicalWedge(phi=2*np.pi, theta=np.pi/4, z=np.array([0, 1.0]), z_offset=0.4, r_min=0.3) #wedge = ToricWedge(r_torus=1.0, r_tube=[0.25, 1.5], phi=np.pi, theta=np.array([-np.pi, 0])) print('V =', wedge.volume()) print('S = ', wedge.surface_area()) joint_vis = Visual.FigureView(fig, joint_disc, color=(0, 1, 0)) rod_vis = Visual.FigureView(fig, rod) box_vis = Visual.FigureView(fig, box)
from Space.Coordinates import Cartesian import Space_visualization as Visual # Euler's angles are used in the proper notation Z (phi1) - X' (Phi) - Z" (phi2) # phi1 and phi2 are defined to have modulo 2*pi radians [-pi; pi] or [0; 2*pi] # Phi is defined to have modulo pi radians [-pi/2; pi/2] or [0; pi] M = 10 N = 5 # Here we use degrees and numpy deg2rad for conversion scale = min(360 / (2 * M), 180 / (2 * N)) # scale factor for mayavi scene fig = mlab.figure('CS demo', bgcolor=(0, 0, 0)) # Create the mayavi figure for phi1 in np.linspace(0, 360, M, endpoint=True): for Phi in np.linspace(0, 180, N, endpoint=True): for phi2 in np.linspace(0, 360, M, endpoint=True): euler_angles = np.deg2rad(np.array([phi1, Phi, phi2])) # Create cartesian coordinate system CS = Cartesian(origin=np.array([phi1, Phi, phi2]), labels=['i1', 'i2', 'i3'],) #euler_angles_convention='Bunge') # Set CS orientation using Euler's angles CS.euler_angles = euler_angles # CS_box visualize CS as a cube colored according to Euler's angles Visual.draw_coordinate_system_box(fig, CS, scale=scale, draw_axes=False) # mlab.outline(extent=[0, 360, 0, 180, 0, 360]) # uncomment to draw white outline mlab.show()