1 |
|
---|
2 |
|
---|
3 | import numpy as np
|
---|
4 | import simulation_helpers as sh
|
---|
5 |
|
---|
6 | #
|
---|
7 | # This is a simple implementation I have looked up in the wiki
|
---|
8 | # THIS ONE is used by Turnable class currently
|
---|
9 | #
|
---|
10 | def make_rotation_matrix( nn, a ):
|
---|
11 | """ return rotation matrix for angle a around nn """
|
---|
12 | R = np.zeros( (3,3) )
|
---|
13 | R[0,0] = nn[0]*nn[0] * (1-np.cos(a)) + np.cos(a)
|
---|
14 | R[1,0] = nn[0]*nn[1] * (1-np.cos(a)) + nn[2]*np.sin(a)
|
---|
15 | R[2,0] = nn[0]*nn[2] * (1-np.cos(a)) - nn[1]*np.sin(a)
|
---|
16 |
|
---|
17 | R[0,1] = nn[0]*nn[1] * (1-np.cos(a)) - nn[2]*np.sin(a)
|
---|
18 | R[1,1] = nn[1]*nn[1] * (1-np.cos(a)) + np.cos(a)
|
---|
19 | R[2,1] = nn[1]*nn[2] * (1-np.cos(a)) + nn[0]*np.sin(a)
|
---|
20 |
|
---|
21 | R[0,2] = nn[0]*nn[2] * (1-np.cos(a)) + nn[1]*np.sin(a)
|
---|
22 | R[1,2] = nn[1]*nn[2] * (1-np.cos(a)) - nn[0]*np.sin(a)
|
---|
23 | R[2,2] = nn[2]*nn[2] * (1-np.cos(a)) + np.cos(a)
|
---|
24 |
|
---|
25 | return R
|
---|
26 |
|
---|
27 | #
|
---|
28 | # This is a smarter implementation I have looked up on the web somewhere
|
---|
29 | # I have timed it and it seems not to be faster then the upper one
|
---|
30 | # However the returned rotation matrices of both differ by a sign
|
---|
31 | # in two off axis elements... not sure what this means :-|
|
---|
32 | #
|
---|
33 | def make_axis_rotation_matrix(direction, angle):
|
---|
34 | """
|
---|
35 | Create a rotation matrix corresponding to the rotation around a general
|
---|
36 | axis by a specified angle.
|
---|
37 | R = dd^T + cos(a) (I - dd^T) + sin(a) skew(d)
|
---|
38 | Parameters:
|
---|
39 | angle : float a
|
---|
40 | direction : array d
|
---|
41 | """
|
---|
42 | d = np.array(direction, dtype=np.float64)
|
---|
43 | d /= np.linalg.norm(d)
|
---|
44 | eye = np.eye(3, dtype=np.float64)
|
---|
45 | ddt = np.outer(d, d)
|
---|
46 | skew = np.array([[ 0, d[2], -d[1]],
|
---|
47 | [-d[2], 0, d[0]],
|
---|
48 | [d[1], -d[0], 0]], dtype=np.float64)
|
---|
49 | mtx = ddt + np.cos(angle) * (eye - ddt) + np.sin(angle) * skew
|
---|
50 | return mtx
|
---|
51 |
|
---|
52 |
|
---|
53 | class Turnable( object ):
|
---|
54 | """ *Virtual* class for inheritance of turn() method only
|
---|
55 |
|
---|
56 | turn( axis, angle) - turn any member of class, which is
|
---|
57 | contained in list-like self._turnables.
|
---|
58 |
|
---|
59 | sub-class constructor should fill self._turnables
|
---|
60 | """
|
---|
61 | def turn(self, axis, angle):
|
---|
62 | """ turn all members in self.turnables around *axis* by angle
|
---|
63 |
|
---|
64 | *axis* : can be any 3-element np.array or np.array - constructable
|
---|
65 | like e.g. a list
|
---|
66 | *angle* : in radians
|
---|
67 | """
|
---|
68 |
|
---|
69 | axis = np.array(axis)
|
---|
70 |
|
---|
71 | if sh.length(axis) != 1.:
|
---|
72 | axis /= sh.length(axis)
|
---|
73 |
|
---|
74 | R = make_rotation_matrix( axis, angle )
|
---|
75 |
|
---|
76 | for turnable in self._turnables:
|
---|
77 | if hasattr(self, turnable):
|
---|
78 | setattr( self, turnable, np.dot(R, getattr( self, turnable)) )
|
---|
79 |
|
---|
80 | # standard __repr__
|
---|
81 | def __repr__( self ):
|
---|
82 | return "%s(%r)" % (self.__class__, self.__dict__)
|
---|
83 |
|
---|