MAGIKS  1.1
Manipulator General Inverse Kinematic Solver
 All Classes Namespaces Files Functions Variables Pages
geometry.py
Go to the documentation of this file.
1 ## @file geometry.py
2 # @brief This module contains a comprehensive data structure with relevant method and properties
3 # for identities in three-dimensional geometry like a point, a rotation or orinetation in 3D space, an ellipsoid and etc.
4 # @author Nima Ramezani Taghiabadi
5 #
6 # PhD Researcher
7 # Faculty of Engineering and Information Technology
8 # University of Technology Sydney (UTS)
9 # Broadway, Ultimo, NSW 2007, Australia
10 # Phone No. : 04 5027 4611
11 # Email(1) : nima.ramezani@gmail.com
12 # Email(2) : Nima.RamezaniTaghiabadi@uts.edu.au
13 # @version 3.0
14 #
15 # start date: 02 May 2015
16 # Last Revision: 02 May 2015
17 
18 import math, sys, numpy as np, trigonometry as trig, rotation as rot, general_python as genpy
19 
20 from math_tools.algebra import vectors_and_matrices as vm, quaternions as quat, optimization as opt
21 from math_tools import general_math as gen
22 
23 
24 '''
25 Changes from version 2:
26 All cgkit functions removed
27 '''
28 """
29 References:
30 
31  [1] Olivier A. Bauchau et.al, "The Vectorial Parameterization of Rotation", Nonlinear Dynamics, 32, No 1, pp 71 - 92, 2003
32 """
33 
34 '''
35 i_uv = np.array([1.0, 0.0, 0.0])
36 j_uv = np.array([0.0, 1.0, 0.0])
37 k_uv = np.array([0.0, 0.0, 1.0])
38 
39 backward_rotmat = np.append(np.append([j_uv],[-k_uv],axis = 0), [-i_uv], axis = 0).T
40 left_rotmat = np.append(np.append([k_uv],[i_uv],axis = 0), [j_uv], axis = 0).T
41 right_rotmat = np.append(np.append([-k_uv],[i_uv],axis = 0), [-j_uv], axis = 0).T
42 upward_rotmat = np.eye(3)
43 downward_rotmat = np.append(np.append([-i_uv],[j_uv],axis = 0), [-k_uv], axis = 0).T
44 
45 ori_backward = Orientation(backward_rotmat)
46 param_set = [
47  'pm_angle_axis' ,
48  'pm_unit_quaternion' ,
49  'pm_angular_spherical' ,
50  'pm_vectorial_identity' ,
51  'pm_vectorial_Cayley_Gibbs_Rodrigues' ,
52  'pm_vectorial_Wiener_Milenkovic' ,
53  'pm_vectorial_linear' ,
54  'pm_vectorial_reduced_Euler_Rodrigues' ,
55  'pm_vectorial_normailized_quaternion' ,
56  'pm_angular_Euler_Kardan'
57  ]
58 '''
59 
60 ## This class, introduces a structure for a point in the three-dimensional space.
61 class Point_3D(object):
62 
63  ## Class Constructor
64  # @param pos The desired position vector at the key point
65  # @param vel The desired velocity vector at the key point
66  # @param acc The desired acceleration vector at the key point
67  def __init__(self, pos, vel = None, acc = None, representation = 'cartesian'):
68 
69  ## An integer indicating the dimension of space in which the kepy point is defined.
70  # This number specifies the number of elements of position, velocity and acceleration vectors
71  self.dim = len(pos)
72 
73  self.__setitem__(representation, pos)
74  self.set_velocity(vel, representation)
75  self.set_acceleration(acc, representation)
76 
77  def clear(self):
78  # A numpy vector indicating the position of the point in cartesian coordinates
79  self.p = None
80 
81  # A numpy vector indicating the position of the point in spherical coordinates
82  self.s = None
83 
84  # A numpy vector indicating the position of the point in cylindrical coordinates
85  self.c = None
86 
87  def clear_velocity(self):
88  # A numpy vector indicating the velocity of the point in cartesian coordinates
89  self.pd = None
90 
91  # A numpy vector indicating the velocity of the point in spherical coordinates
92  self.sd = None
93 
94  # A numpy vector indicating the velocity of the point in cylindrical coordinates
95  self.cd = None
96 
97  def clear_acceleration(self):
98  # A numpy vector indicating the acceleration of the point in cartesian coordinates
99  self.pdd = None
100  # A numpy vector indicating the acceleration of the point in spherical coordinates
101  self.sdd = None
102  # A numpy vector indicating the acceleration of the point in cylindrical coordinates
103  self.cdd = None
104 
105  def __getitem__(self, representation):
106  if representation == 'cartesian':
107  return self.cartesian()
108  elif representation == 'cartesian_velocity':
109  return self.cartesian_velocity()
110  elif representation == 'cartesian_acceleration':
111  return self.cartesian_acceleration()
112  if representation == 'spherical':
113  return self.spherical()
114  elif representation == 'spherical_velocity':
115  return self.spherical_velocity()
116  elif representation == 'spherical_acceleration':
117  return self.spherical_acceleration()
118  if representation == 'cylindrical':
119  return self.cylindrical()
120  elif representation == 'cylindrical_velocity':
121  return self.cylindrical_velocity()
122  elif representation == 'cylindrical_acceleration':
123  return self.cylindrical_acceleration()
124  else:
125  assert False, genpy.err_str(__name__ , self.__class__.__name__ , '__getitem__', representation + ' is not a valid value for representation')
126 
127  def is_none(self) :
128  return self.p == None
129 
130  def velocity_is_none(self) :
131  return self.pd == None
132 
134  return self.pdd == None
135 
136  def set_velocity(self, value, representation):
137  self.clear_velocity()
138  if representation == 'cartesian':
139  self.pd = value
140  elif representation == 'spherical':
141  self.sd = value
142  elif representation == 'cylindrical':
143  self.cd = value
144  else:
145  assert False, genpy.err_str(__name__ , self.__class__.__name__ , 'set_velocity', representation + ' is not a valid value for representation')
146 
147  def set_acceleration(self, value, representation):
148  self.clear_acceleration()
149  if representation == 'cartesian':
150  self.pdd = value
151  elif representation == 'spherical':
152  self.sdd = value
153  elif representation == 'cylindrical':
154  self.cdd = value
155  else:
156  assert False, genpy.err_str(__name__ , self.__class__.__name__ , 'set_acceleration', representation + ' is not a valid value for representation')
157 
158  def __setitem__(self, representation, value):
159  self.clear()
160  if representation == 'cartesian':
161  self.p = value
162  elif representation == 'spherical':
163  '''
164  s[0] = ro
165  s[1] = theta
166  s[2] = phi
167  '''
168  self.s = value
169  elif representation == 'cylindrical':
170  '''
171  c[0] = r
172  c[1] = theta
173  c[2] = z
174  '''
175  self.c = value
176  else:
177  assert False, genpy.err_str(__name__ , self.__class__.__name__ , '__setitem__', representation + ' is not a valid value for representation')
178 
179  def cartesian(self):
180  if self.p != None:
181  return self.p
182  elif self.s != None:
183  self.p = np.zeros(3)
184  self.p[0] = self.s[0]*math.cos(self.s[1])*math.cos(self.s[2])
185  self.p[1] = self.s[0]*math.sin(self.s[1])*math.cos(self.s[2])
186  self.p[2] = self.s[0]*math.sin(self.s[2])
187  return self.p
188  elif self.c != None:
189  self.p = np.zeros(3)
190  self.p[0] = self.c[0]*math.cos(self.c[1])
191  self.p[1] = self.c[0]*math.sin(self.c[1])
192  self.p[2] = self.c[2]
193  return self.p
194  else:
195  return None
196 
197  def spherical(self):
198  if self.s == None:
199  self.s = np.zeros(3)
200  [r, t, z] = self.cylindrical()
201  self.s[0] = math.sqrt(r*r + z*z) # ro
202  self.s[1] = t # theta
203  self.s[2] = math.atan2(z, r) # phi
204  return self.s
205 
206  def cylindrical(self):
207  if self.c == None:
208  self.c = np.zeros(3)
209  [x, y, z] = self.cartesian()
210  self.c[0] = math.sqrt(x*x + y*y) # r
211  self.c[1] = math.atan2(y, x) # theta
212  self.c[2] = z
213  return self.c
214 
215  def dist(self, point):
216  p1 = self.cartesian()
217  p2 = point.cartesian()
218  return np.linalg.norm(p1 - p2)
219 
220  ## This function is the string representation of the key point
221  # @param None
222  # @return A string representing all the information about the key point
223  def __str__( self ):
224  s = "Point Dimension: " + str(self.dim) + '\n'
225 
226  if self.p != None:
227  s += "Position : " + str(self.p) + '\n'
228  if self.pd != None:
229  s += "Velocity : " + str(self.pd) + '\n'
230  if self.pdd != None:
231  s += "Acceleration : " + str(self.pdd) + '\n'
232  return s
233 
234  ## Use this function to get the current value of position, velocity or acceleration in a desired dimension
235  # @param field_name A string, must be selected from
236  # set: ['position', 'velocity', 'acceleration'
237  # specifying which vector is desired.
238  # @param axis A non-negative integer specifying which element of the vector should be returned.
239  # (Must not be greater than the space dimension)
240  # @return A float containing the value of the element specified by argument \b axis from the vector specified by argument \b field_name
241  def value(self, field_name = 'position', axis = 0):
242  assert (axis <= self.dim), "Error from " + __name__ + func_name + ": Argument axis must not esxeed the space dimension"
243  assert (axis >= 0), "Error from " + __name__ + func_name + ": Argument axis can not have a negative value"
244 
245  if field_name == 'position':
246  return self.pos[axis]
247  elif field_name == 'velocity':
248  return self.vel[axis]
249  elif field_name == 'acceleration':
250  return self.acc[axis]
251  else:
252  print "Error from " + __name__ + func_name + ": " + field_name + " is not not a valid value for argument field_name"
253 
254  def __add__(p1, p2):
255  return Point_3D(pos = p1.cartesian() + p2.cartesian())
256 
257  def __sub__(p1, p2):
258  return Point_3D(pos = p1.cartesian() - p2.cartesian())
259 
260  def __neg__(p):
261  return Point_3D(pos = - p.cartesian())
262 
263 ## This class, introduces a rotation in the three-dimensional space.
264 # It supports various representations and convensions of orientation.
265 # This class also supports computation orientation speed represented by various convensions.
266 class Orientation_3D(object):
267 
268  ## private
269  def clear_acceleration(self):
270  ## A numpy vector of size 3 containing \f$ \ddot{\p} \f$ (second derivative of orientation vector \f$ p \f$ w.r.t. time)
271  # where \f$ p \f$ is the vectorial representation of orientation which is defined according to property \b self.parametrization
272  self.pdd = None
273 
274  ## A numpy 3x3 rotation matrix: Representation of orientation acceleration as 3x3 numpy rotation matrix second derivative w.r.t. time
275  self.Rdd = None
276 
277  ## Clears all velocity properties. All velocity properties (self.omega, self.Rd, self.Qd, self.ud, self.pd, self.phid) will be set to None.
278  # @param None
279  # @return None
280  def clear_velocity(self):
281  ## A numpy vector of size 3 containing the <em> angular velocity </em> representation of orientation velocity
282  self.omega = None
283 
284  ## A numpy 3x3 rotation matrix: Representation of orientation velocity as 3x3 numpy rotation matrix derivative w.r.t. time
285  self.Rd = None
286 
287  ## A numpy vector of size 4: Quaternion representation of orientation velocity as a numpy vector (\f$ \frac{ dq }{ dt } \f$)
288  self.Qd = None
289 
290  ## A float containing \f$ \dot{\phi} \f$ (derivative of \f$ \phi \f$ w.r.t. time),
291  # where \f$ \phi \f$ is the \b angle in \em Angle-Axis representation of orientation
292  self.phid = None
293 
294  ## A numpy vector of size 3 containing \f$ \dot{\u} \f$ (derivative of unit vector \f$ u \f$ w.r.t. time)
295  # where \f$ u \f$ is the \b axis in \em Angle-Axis representation of orientation
296  self.ud = None
297 
298  ## A numpy vector of size 3 containing \f$ \dot{\p} \f$ (derivative of orientation vector \f$ p \f$ w.r.t. time)
299  # where \f$ p \f$ is the vectorial representation of orientation which is defined according to property \b self.parametrization
300  self.pd = None
301 
302  ## Clears all rotation properties. All rotation properties (self.R, self.Q, self.u, self.p, self.phi, self.H, self.sa) will be set to None.
303  # @param None
304  # @return None
305  def clear(self):
306  ## A numpy 3x3 rotation matrix: Representation of orientation as 3x3 numpy rotation matrix
307  self.R = None
308 
309  ## A numpy vector of size 4: Quaternion representation of orientation as a numpy vector
310  self.Q = None
311 
312  ## A numpy vector of size 3: Representation of orientation as a non-redundant numpy vector (depends on the generator function)
313  self.p = None
314 
315  ## A float: Angle phi in Angle-Axis representation of orientation
316  self.phi = None
317 
318  ## A numpy vector of size 3: Unit vector u in Angle-Axis representation of orientation
319  self.u = None
320 
321  self.H = None
322 
323  ## A numpy vector of 3 elements: Non-redundant representation of orientation by three <em> Spherical Orientation Angles </em>
324  self.sa = None
325 
326  ## Use this function to find out if a rotation by any convention is defined for the instance
327  # @param None
328  # @return A boolean: True if all rotation properties (self.p, self.R, self.u, self.phi, self.Q) are set to None, False, if otherwise.
329  def is_none(self) :
330  return (self.p == None) and (self.R == None) and (self.u == None) and (self.phi == None) and (self.Q == None)
331 
332  ## Use this function to find out if a rotation velocity is defined for the instance
333  # @param None
334  # @return A boolean: True if all rotation speed properties (self.Rd, self.ud, self.phid, self.Qd, self.pd) are set to None, False, if otherwise.
335  def velocity_is_none(self) :
336  return (self.pd == None) and (self.Rd == None) and (self.ud == None) and (self.phid == None) and (self.Qd == None)
337 
338  ## private
340  return self.pdd == None
341 
342  ## Class Constructor:
343  # @param ori: The orientation or rotation defined
344  # \li A tuple or numpy vector of 4 elements if representation = 'quaternion',
345  # \li A 3 X 3 numpy matrix if representation = 'matrix',
346  # \li A tuple or numpy vector of 4 elements if representation = 'angle_axis',
347  # \li A tuple or numpy vector of 3 elements if representation = 'vector',
348  # @param representation: A string: Must be one of the supported convensions:
349  # \li matrix
350  # \li quaternion
351  # \li angle_axis
352  # \li vector
353  def __init__(self, ori, representation = 'matrix', ori_velocity = None, ori_acceleration = None, parametrization = 'identity'):
354  self.representation = representation
355  self.parametrization = parametrization
356  self.__setitem__(representation, ori)
357  self.m = 1.0
358  if ori_velocity == None:
359  self.clear_velocity()
360  else:
361  self.set_velocity(ori_velocity, representation)
362 
363  if ori_acceleration == None:
364  self.clear_acceleration()
365  else:
366  self.set_acceleration(ori_acceleration, representation)
367 
368  def __str__(self):
369 
370  s = "3D Orientation represented by " + self.representation + ": \n \n"
371  s += str(self[self.representation])
372  s += "\n"
373  return s
374 
375  def tensor(self):
376  if self.H == None:
377  if gen.equal(self.angle(), 0.0) :
378  return np.eye(3)
379 
380  p = self.vector()
381  px = rot.skew(p)
382  px2 = np.dot(px, px)
383  p_nrm = np.linalg.norm(p)
384  p2 = p_nrm*p_nrm
385  p2_inv = gen.inv(p2)
386  v = self.noo()
387  z = self.zeta()
388  m = self.moo()
389  v2 = v*v
390  v2_z = v2*gen.inv(z)
391  self.H = m*np.eye(3) + 0.5*v2*px + p2_inv*(m - v2_z)*px2
392  return self.H
393 
394  def matrix_velocity(self):
395  if self.velocity_is_none():
396  return None
397  elif self.Rd != None:
398  return self.Rd
399  elif self.omega != None:
400  r = self.matrix()
401  wx = rot.skew(self.omega)
402  self.Rd = np.dot(wx, r)
403  elif self.Qd != None:
404  assert False, "Not Supported !"
405  elif (self.phid != None) and (self.ud != None):
406  phi = self.angle()
407  u = self.axis()
408  ux = rot.skew(u)
409  self.omega = self.phid*u + np.dot(math.sin(phi)*np.eye(3) + (1.0 - math.cos(phi))*ux, ud)
410  '''
411  Reference: Olivier A. Bauchau et.al, "The Vectorial Parameterization of Rotation", Nonlinear Dynamics, 32, No 1, pp 71 - 92, 2003 (EQ.10)
412  '''
413  elif self.pd != None:
414  self.omega = np.dot(self.tensor(), self.pd)
415  else:
416  assert False, "This should not happen !"
417 
418  return self.matrix_velocity()
419 
420  def angular_velocity(self):
421  if self.velocity_is_none():
422  return None
423  elif self.omega == None:
424  rd = self.matrix_velocity()
425  r = self.matrix()
426  # Ref [1]: Equation 9
427  self.omega = rot.axial(np.dot(rd, r.T))
428  return self.omega
429 
431  if self.velocity_is_none():
432  return None
433  elif self.Qd == None:
434  '''
435  r = self.matrix()
436  rd = self.matrix_velocity()
437  self.Qd = quaternions.unit_quaternion_velocity(r, rd)
438  '''
439  phi = self.angle()
440  phid = self.angle_velocity()
441  u = self.axis()
442  ud = self.axis_velocity()
443  s = math.sin(phi/2)
444  c = math.cos(phi/2)
445  wd = - 0.5*s*phid
446  ed = 0.5*c*phid*u + s*ud
447  self.Qd = np.array([wd, ed[0], ed[1], ed[2]])
448  return self.Qd
449 
450  def angle_velocity(self):
451  if self.velocity_is_none():
452  return None
453  elif self.phid == None:
454  phi = self.angle()
455  rd = self.matrix_velocity()
456  sin_phi = math.sin(phi)
457  self.phid = np.trace(rd)/(-2*sin_phi)
458  return self.phid
459 
460  def axis_velocity(self):
461  if self.velocity_is_none():
462  return None
463  elif self.ud == None:
464  u = self.axis()
465  phi = self.angle()
466  sin_phi = math.sin(phi)
467  cos_phi = math.cos(phi)
468  phid = self.angle_velocity()
469  rd = self.matrix_velocity()
470  axrd = rot.axial(rd)
471 
472  self.ud = (axrd - cos_phi*phid*u)/sin_phi
473  return self.ud
474 
475  def matrix(self):
476  if self.R != None:
477  return self.R
478 
479  elif self.Q != None:
480  self.R = rot.rotation_matrix(self.Q)
481  return self.matrix()
482 
483  elif (self.phi != None) and (self.u != None):
484  ux = rot.skew(self.u)
485  self.R = np.eye(3) + math.sin(self.phi)*ux + (1.0 - math.cos(self.phi))*np.dot(ux,ux)
486  return self.R
487 
488  elif self.p != None:
489  px = rot.skew(self.p)
490  px2 = np.dot(px, px)
491  p = np.linalg.norm(self.p)
492  self.phi = self.gen_fun_inv(p)
493  v = self.noo()
494  z = self.zeta()
495  v2 = v*v
496  v2_z = v2*gen.inv(z)
497  self.R = np.eye(3) + v2_z*px + 0.5*v2*px2
498  return self.R
499 
500  else:
501  return None
502 
503  def vector(self):
504  if self.p == None:
505  if (self.parametrization == 'linear') and (self.m == 1.0): # Special Case: Linear parametrization p(phi) = sin(phi)
506  self.p = rot.axial(self.matrix())
507  return self.p
508  else:
509  phi = self.angle()
510  f = self.gen_fun(phi)
511 
512  self.p = f*self.axis()
513  return self.p
514 
515  def vector_velocity(self):
516  if self.velocity_is_none():
517  return None
518  elif self.pd == None:
519  if (self.parametrization == 'linear') and (self.m == 1.0): # Special Case: Linear parametrization p(phi) = sin(phi)
520  self.pd = rot.axial(self.matrix_velocity())
521  return self.pd
522  else:
523  phi = self.angle()
524  f = self.gen_fun(phi)
525  fp = self.gen_fun_derivative(phi)
526 
527  self.pd = fp*self.angle_velocity()*self.axis()+f*self.axis_velocity()
528  return self.pd
529 
531  return self.pdd
532 
533  ## Sets the parametrization for the generating function in vectorial representation of orientation.
534  # @param parametrization A string specifying the parametrization. Valid values are:
535  # 'identity', 'linear', 'cayley-gibbs-rodrigues', 'bauchau-trainelli', 'exponential'
536  # @return None
537  def set_parametrization(self, parametrization = 'identity'): # p(phi) = (phi/m)
538  valid_parametrizations = ['identity', 'linear', 'cayley-gibbs-rodrigues', 'bauchau-trainelli', 'exponential']
539  genpy.check_valid(parametrization, valid_parametrizations, __name__, self.__class__.__name__,sys._getframe().f_code.co_name, 'parametrization')
540  if parametrization != self.parametrization:
541  self.parametrization = parametrization
542  self.p = None
543  self.pd = None
544  if self.parametrization in ['cayley-gibbs-rodrigues']:
545  self.m = 2.0
546  else:
547  self.m = 1.0
548 
549  ## Returns the value of the generating function for the given angle phi
550  # @param phi A float variable specifying the angle
551  # @return A float containing the value of the generating function for the given phi.
552  # The generating function depends on property self.parametrization
553  def gen_fun(self, phi):
554  genpy.check_type(phi, [float, np.float64], __name__, self.__class__.__name__,sys._getframe().f_code.co_name, 'phi')
555  if self.parametrization == 'linear': # generating function: p(phi) = m*sin(phi/m)
556  return self.m*math.sin(phi/self.m)
557  elif self.parametrization == 'identity': # p(phi) = phi/m (m = 1.0)
558  return phi/self.m
559  elif self.parametrization == 'cayley-gibbs-rodrigues': # p(phi) = m*tan(phi/m) (m = 2)
560  return self.m*math.tan(phi/self.m)
561  elif self.parametrization == 'bauchau-trainelli': # p(phi) = (6*(phi - sin(phi)))**(1.0/3.0)
562  s = math.sin(phi)
563  a = 6*(phi - s)
564  return a**0.33333333
565  elif self.parametrization == 'exponential': # p(phi) = exp(phi)-1
566  return math.exp(phi) - 1.0
567  else:
568  assert False,"Not Supported!"
569 
570  def gen_fun_inv(self, p):
571  if self.parametrization == 'linear': # generating function: p(phi) = m*sin(phi/m)
572  return self.m*trig.arcsin(p/self.m)
573  elif self.parametrization == 'identity': # p(phi) = phi/m (m = 1)
574  return self.m*p
575  elif self.parametrization == 'cayley-gibbs-rodrigues': # p(phi) = m*tan(phi/m) (m = 2)
576  return self.m*trig.arctan(p/self.m)
577  elif self.parametrization == 'bauchau-trainelli': # p(phi) = (6*(phi - sin(phi)))**(1.0/3.0)
578  assert False, "Not Supported!"
579  elif self.parametrization == 'exponential': # p(phi) = exp(phi)-1
580  return math.log(p+1.0)
581  else:
582  assert False,"Not Supported!"
583 
584  def gen_fun_derivative(self, phi):
585  if self.parametrization == 'linear':
586  return math.cos(phi/self.m)
587  elif self.parametrization == 'identity':
588  return 1.0/self.m
589  elif self.parametrization == 'cayley-gibbs-rodrigues':
590  t = math.tan(phi/self.m)
591  return 1.0 + t*t
592  elif self.parametrization == 'bauchau-trainelli': # Bauchau-Trainelli parametrization
593  s = math.sin(phi)
594  c = math.cos(phi)
595  a = 6*(phi - s)
596  f = a**0.33333333
597  b = gen.inv(f)
598  return 2*(1.0-c)*b*b
599  elif self.parametrization == 'exponential': # Exponential
600  return math.exp(phi)
601  else:
602  assert False,"Not Supported!"
603 
604  def noo(self, phi = None):
605  if phi == None:
606  phi = self.angle()
607 
608  if gen.equal(phi, 0.0) and self.parametrization == 'identity':
609  return self.m
610 
611  p = self.gen_fun(phi)
612  return 2*math.sin(phi/2)*gen.inv(p)
613 
614  def zeta(self, phi = None):
615  if phi == None:
616  phi = self.angle()
617 
618  if gen.equal(phi, 0.0) and self.parametrization == 'identity':
619  return self.m
620 
621  p = self.gen_fun(phi)
622  return 2*math.tan(phi/2)*gen.inv(p)
623 
624  def moo(self, phi = None):
625  if phi == None:
626  phi = self.angle()
627  pp = self.gen_fun_derivative(phi)
628  return gen.inv(pp)
629 
630  def quaternion(self):
631  if self.Q == None:
632  r = self.matrix()
633  self.Q = quat.unit_quaternion(r)
634 
635  '''
636  phi = self.angle()
637  u = self.axis()
638  e = math.sin(phi/2)*u
639  w = math.cos(phi/2)
640  self.Q = np.array([w, e[0], e[1], e[2]])
641  '''
642  # Q = self.quaternion_cgt()
643  # self.Q = np.array([Q.w, Q.x, Q.y, Q.z])
644  return self.Q
645 
646  def angle(self):
647  if self.phi == None:
648  if self.p != None:
649  self.phi = self.gen_fun_inv(np.linalg.norm(self.p))
650  else:
651  # Alternative 1: (self.phi, self.u_cgt) = self.quaternion_cgt().toAngleAxis()
652  # Alternative 2: self.phi = trig.arccos(0.5*(np.trace(self.matrix()) - 1.0))
653  # Alternative 3
654  '''
655  r = self.matrix()
656  ax = rot.angle_axis(r)
657  self.phi = ax[0]
658  self.u = ax[1:4]
659  '''
660  self.phi = trig.arccos(0.5*(np.trace(self.matrix()) - 1.0))
661 
662  return self.phi
663 
664  def spherical(self):
665  if self.sa == None:
666  self.sa = np.zeros((3))
667  ax = self.angle_axis()
668  self.sa[0] = ax[0]
669  self.sa[2] = math.atan2(ax[2], ax[1])
670  self.sa[1] = trig.arccos(ax[3])
671 
672  return self.sa
673 
674  def angle_axis(self):
675  u = self.axis()
676  return np.array([self.angle(), u[0], u[1], u[2]])
677 
678  def axis(self):
679  if self.u == None:
680  r = self.matrix()
681  ax = rot.angle_axis(r)
682  self.phi = ax[0]
683  self.u = ax[1:4]
684 
685  return self.u
686 
687  def frame_axis(self, k):
688  r = self.matrix()
689  return r[0:3, k]
690 
691  def __setitem__(self, representation, value):
692 
693  self.clear()
694  if representation == 'matrix':
695  self.R = value
696  elif representation == 'quaternion':
697  self.Q = value
698  elif representation == 'angle_axis':
699  self.phi = value[0]
700  self.u = value[1:4]
701  elif representation == 'vector':
702  self.p = value
703  else:
704  assert False, genpy.err_str(__name__ , self.__class__.__name__ , '__setitem__', representation + ' is not a valid value for representation')
705 
706  def __getitem__(self, representation):
707  if representation == 'matrix':
708  return self.matrix()
709  elif representation == 'quaternion':
710  return self.quaternion()
711  elif representation == 'angle_axis':
712  return self.angle_axis()
713  elif representation == 'angle':
714  return self.angle()
715  elif representation == 'axis':
716  return self.axis()
717  elif representation == 'vector':
718  return self.vector()
719  elif representation == 'trace':
720  return np.trace(self.matrix())
721  elif representation == 'diag':
722  return np.diag(self.matrix())
723  elif representation == 'angular_spherical':
724  return self.spherical()
725  elif representation == 'matrix_velocity':
726  return self.matrix_velocity()
727  elif representation == 'quaternion_velocity':
728  return self.quaternion_velocity()
729  elif representation == 'angle_axis_velocity':
730  u = self.axis_velocity()
731  return np.array([self.angle_velocity(), u[0], u[1], u[2]])
732  elif representation == 'angle_velocity':
733  return self.angle_velocity()
734  elif representation == 'axis_velocity':
735  return self.axis_velocity()
736  elif representation == 'vector_velocity':
737  return self.vector_velocity()
738  elif representation == 'vector_acceleration':
739  return self.vector_acceleration()
740  elif representation == 'trace_velocity':
741  return np.trace(self.matrix_velocity())
742  elif representation == 'diag_velocity':
743  return np.diag(self.matrix_velocity())
744  else:
745  assert False, genpy.err_str(__name__ , self.__class__.__name__ , '__getitem__', representation + ' is not a valid value for representation')
746 
747  def set_acceleration(self, ori_dd, representation = None):
748  self.clear_acceleration()
749  if representation == 'vector':
750  self.pdd = oridd
751  else:
752  assert False, genpy.err_str(__name__ , self.__class__.__name__ , '__getitem__', representation + ' is not a valid value for representation')
753 
754  def set_velocity(self, value, representation = None):
755  self.clear_velocity()
756  if representation == None:
757  representation = self.representation
758  if representation == 'quaternion':
759  self.Qd = value
760  elif representation == 'matrix':
761  self.Rd = value
762  elif representation == 'angle_axis':
763  self.phid = value[0]
764  self.ud = value[1:4]
765  elif representation == 'vector':
766  self.pd = value
767  else:
768  assert False, "Not supported Yet !"
769 
770  def set_acceleration(self, value, representation = None):
771  self.clear_acceleration()
772  if representation == None:
773  representation = self.representation
774  if representation == 'vector':
775  self.pdd = value
776  elif representation == 'matrix':
777  self.Rdd = value
778  else:
779  assert False, genpy.err_str(__name__ , self.__class__.__name__ , 'set_acceleration', representation + ' is not a valid value for representation')
780 
781  def get_velocity(self, representation = None):
782  if representation == None:
783  representation = self.representation
784 
785  if representation == 'quaternion':
786  return self.quaternion_velocity()
787  elif representation == 'matrix':
788  return self.matrix_velocity()
789  elif representation == 'angle_axis':
790  return self.angle_axis_velocity()
791  elif representation == 'angular_spherical':
792  assert False
793  return self.spherical_velocity()
794  else:
795  assert False, "Not supported Yet !"
796 
797  def __div__(o1, o2):
798  r1 = o1.matrix()
799  r2 = o2.matrix()
800  r1_dot = o1.matrix_velocity()
801  r2_dot = o2.matrix_velocity()
802  r = np.dot(r1, r2.T)
803  if (r1_dot == None) or (r2_dot == None):
804  o = Orientation_3D(r)
805  else:
806  r_dot = np.dot(r1_dot, r2.T) + np.dot(r1, r2_dot.T)
807  o = Orientation_3D(r, ori_velocity = r_dot)
808 
809  if o1.parametrization == o2.parametrization:
810  o.set_parametrization(o1.parametrization)
811  else:
812  o.parametrization = None
813  o.representation = o1.representation
814  return o
815 
816  def __mul__(o1, o2):
817  r1 = o1.matrix()
818  r2 = o2.matrix()
819  r1_dot = o1.matrix_velocity()
820  r2_dot = o2.matrix_velocity()
821  r = np.dot(r1, r2)
822  if (r1_dot == None) or (r2_dot == None):
823  o = Orientation_3D(r)
824  else:
825  r_dot = np.dot(r1_dot, r2) + np.dot(r1, r2_dot)
826  o = Orientation_3D(r, ori_velocity = r_dot)
827 
828  if o1.parametrization == o2.parametrization:
829  o.set_parametrization(o1.parametrization)
830  else:
831  o.parametrization = None
832  o.representation = o1.representation
833  return o
834 
835 class Ellipsoid(object):
836  ## Class Constructor
837  # Creates an ellipsoid with given charachteristic matrix A and center. The equation of the ellipsoid is given as:
838  # $$
839  # **(x - c)**^T \cdot **M** \cdot **(x - c)**
840  # $$
841  # @param M A numpy square matrix representing the charachteristic matrix of the ellipsoid.
842  # @param center An instance of class Point_3D() specifying the ellipsoid center
843  def __init__(self, M = np.eye(3), center = Point_3D(pos = np.zeros(3))):
844  '''
845  For example to have a non-rotated ellipsoid centered at the origin with equation:
846  x^2/a^2 + y^2/b^2 + z^2/c^2 = 1
847  Arguments M and center must be selected as:
848  [ a^(-2) 0 0 ]
849  M = [ 0 b^(-2) 0 ]
850  [ 0 0 c^(-2) ]
851 
852  center = (0, 0, 0)
853  '''
854  # Checking arguments:
855  func_name = sys._getframe().f_code.co_name
856  genpy.check_type(M, [np.ndarray], __name__, self.__class__.__name__, func_name, 'M', shape = (3,3))
857  (landa, V) = np.linalg.eig(M)
858  # V is a rotation that transforms from principal coordinate system to the actual coordinate system
859  # if x is a vector in principal CS and x' is its representation in actual CS: x' = V*x and x = V^T*x'
860  assert vm.positive(landa, non_zero = True) and gen.equal(np.linalg.norm(V.imag) , 0.0), genpy.err_str(__name__, self.__class__.__name__, func_name, 'Matrix M must have real and positive eigen values')
861  #
862  self.M = M
863  self.center = center
864  self.a = math.sqrt(1.0/landa[0])
865  self.b = math.sqrt(1.0/landa[1])
866  self.c = math.sqrt(1.0/landa[2])
867  self.R = V.real
868 
869  def volume(self):
870  return (4.0/3.0)*math.pi*self.a*self.b*self.c
871 
872  def min_dist(self, point):
873  p0 = np.dot(self.R, point.cartesian() - self.center['cartesian'])
874  (theta, phi) = opt.distance_from_ellipsoid(a = self.a, b = self.b, c = self.c, x0 = p0[0], y0 = p0[1], z0 = p0[2], silent = False)
875  px = self.a*math.cos(theta)*math.cos(phi)
876  py = self.b*math.sin(theta)*math.cos(phi)
877  pz = self.c*math.sin(phi)
878  pp = np.array([px, py, pz])
879  return Point_3D(pos = np.dot(self.R, pp) + self.center['cartesian'])
880 
881  def max_dist(self, point):
882  p0 = np.dot(self.R, point.cartesian() - self.center['cartesian'])
883  (theta, phi) = opt.distance_from_ellipsoid(a = self.a, b = self.b, c = self.c, x0 = p0[0], y0 = p0[1], z0 = p0[2], silent = False, maximum = True)
884  px = self.a*math.cos(theta)*math.cos(phi)
885  py = self.b*math.sin(theta)*math.cos(phi)
886  pz = self.c*math.sin(phi)
887  pp = np.array([px, py, pz])
888  return Point_3D(pos = np.dot(self.R, pp) + self.center['cartesian'])
889 
890  def possess(self, point):
891  x_c = point.cartesian() - self.center.cartesian()
892  d = np.dot(np.dot((x_c).T, self.M), x_c)
893  return gen.equal(d, 1.0)
def __str__
This function is the string representation of the key point.
Definition: geometry.py:223
pdd
A numpy vector of size 3 containing (second derivative of orientation vector w.r.t.
Definition: geometry.py:272
def __init__
Class Constructor Creates an ellipsoid with given charachteristic matrix A and center.
Definition: geometry.py:843
def clear
Clears all rotation properties.
Definition: geometry.py:305
def is_none
Use this function to find out if a rotation by any convention is defined for the instance.
Definition: geometry.py:329
Rdd
A numpy 3x3 rotation matrix: Representation of orientation acceleration as 3x3 numpy rotation matrix ...
Definition: geometry.py:275
pd
A numpy vector of size 3 containing (derivative of orientation vector w.r.t.
Definition: geometry.py:300
def gen_fun
Returns the value of the generating function for the given angle phi.
Definition: geometry.py:553
dim
An integer indicating the dimension of space in which the kepy point is defined.
Definition: geometry.py:71
ud
A numpy vector of size 3 containing (derivative of unit vector w.r.t.
Definition: geometry.py:296
Qd
A numpy vector of size 4: Quaternion representation of orientation velocity as a numpy vector ( ) ...
Definition: geometry.py:288
Rd
A numpy 3x3 rotation matrix: Representation of orientation velocity as 3x3 numpy rotation matrix deri...
Definition: geometry.py:285
R
A numpy 3x3 rotation matrix: Representation of orientation as 3x3 numpy rotation matrix.
Definition: geometry.py:307
This class, introduces a rotation in the three-dimensional space.
Definition: geometry.py:266
p
A numpy vector of size 3: Representation of orientation as a non-redundant numpy vector (depends on t...
Definition: geometry.py:313
def __init__
Class Constructor.
Definition: geometry.py:67
u
A numpy vector of size 3: Unit vector u in Angle-Axis representation of orientation.
Definition: geometry.py:319
def velocity_is_none
Use this function to find out if a rotation velocity is defined for the instance. ...
Definition: geometry.py:335
def value
Use this function to get the current value of position, velocity or acceleration in a desired dimensi...
Definition: geometry.py:241
phid
A float containing (derivative of w.r.t.
Definition: geometry.py:292
omega
A numpy vector of size 3 containing the angular velocity representation of orientation velocity...
Definition: geometry.py:282
This class, introduces a structure for a point in the three-dimensional space.
Definition: geometry.py:61
phi
A float: Angle phi in Angle-Axis representation of orientation.
Definition: geometry.py:316
sa
A numpy vector of 3 elements: Non-redundant representation of orientation by three Spherical Orienta...
Definition: geometry.py:324
def clear_velocity
Clears all velocity properties.
Definition: geometry.py:280
Q
A numpy vector of size 4: Quaternion representation of orientation as a numpy vector.
Definition: geometry.py:310
def set_parametrization
Sets the parametrization for the generating function in vectorial representation of orientation...
Definition: geometry.py:537