目次

geo.pyの基本的な使い方

geo_basic

I wrote a module called geo.py that performs 3D geometric operations such as vectors, rotation matrices, and coordinate transformations.

This ipynb file shows a basic usage of the geo module.

This was run under the following conditions, - ProBook 474s, メモリ:8 GB,CPU:Core™ i5-3230M,OS: Ubuntu 20.04 - jupyter notebook,python3

The file is matrix_vs_quaternion.ipynb.

import module

Note: geo.py imports the math module in the form “from math import *”.

geo.py defines the VECTOR class, MATRIX class, QUATERNION class, and FRAME class. The class names are all capitalized to avoid name collisions with other similar classes.

from geo import *

VECTOR

VECTOR class is defined as a subclass of list.

class VECTOR(list) :
    def __init__(self, x=0.0, y=0.0, z=0.0, vec=[]) :  # vec is provided  to create a copy of a VECTOR.
    def __repr__(self) : 
    def dot(self, other) : # inner product
    def __neg__(self) :  # negative vector
    def __add__(self, other) : # addition
    def __radd__(self, other) : # addition to avoid list concatenation
    def __sub__(self, other) : # subtraction
    def __mul__(self, other) : # cross product
    def __rmul__(self, other) : # multiplication with scalar and MATRIX(this is defined in MATRIX)
    def __abs__(self) : # absolute value
    def normalize(self) : # normalizetion

generationg VECTORs

v1=VECTOR(1,2,3)
v2=VECTOR(y=3)
print(v1)
print(v2)
v:[1.0, 2.0, 3.0]
v:[0.0, 3.0, 0.0]

addition and subtraction

v1+v2
v:[1.0, 5.0, 3.0]
v1-v2
v:[1.0, -1.0, 3.0]

inner product

v1.dot(v2)
6.0

cross product

v1 * v2
v:[-9.0, 0.0, 3.0]

scalar multiplication

3*v1
v:[3.0, 6.0, 9.0]
v1*3  
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-20-e77cfd6fc54c> in <module>
----> 1 v1*3


~/openrtm/Robots/core/geo.py in __mul__(self, other)
     24   def __mul__(self, other) : # cross protuct
     25     if not isinstance(other, VECTOR) :
---> 26        raise TypeError('error')
     27     tmp = VECTOR();
     28     tmp[0] = self[1]*other[2] - self[2]*other[1]


TypeError: error

negatification

-v1
v:[-1.0, -2.0, -3.0]

absolute value

abs(v1)
3.7416573867739413

nomalization

v3=v1.normalize()
print("v1: ", v1)
print("v3: ", v3)
print("abs(v3): ", abs(v3))
v1:  v:[1.0, 2.0, 3.0]
v3:  v:[0.2672612419124244, 0.5345224838248488, 0.8017837257372732]
abs(v3):  1.0

exercises

Find the angle between VECTOR(0.866, 0.5, 0) and VECTOR(0.707, 0.707, 0).

a=VECTOR(0.866,0.5,0)
b=VECTOR(0.707,0.707,0)
angle_rad = acos(a.dot(b)/abs(a)/abs(b))
angle_deg = 180*angle_rad/pi
print(angle_deg)
14.999272219172607

Find the rotation angle around the z-axis of VECTOR(-0.707,-0.707, 0) from VECTOR(1,0,0) .

a wrong answer

a=VECTOR(1,0,0)
b=VECTOR(-0.707,-0.707,0)
angle_rad = acos(a.dot(b)/abs(a)/abs(b))
angle_deg = 180*angle_rad/pi
print(angle_deg)
135.0

the right answer

x=VECTOR(1,0,0)
y=VECTOR(0,1,0)
b=VECTOR(-0.707,-0.707,0)
co=x.dot(b)
si=x.dot(b)
angle_rad = atan2(si,co)
angle_deg = 180*angle_rad/pi
print(angle_deg)
-135.0

MATRIX

MATRIX class is defined as subclass of list. It is a list of 3 lists(rows of the matrix).

MATRIX here is not a general matrix. It is an orthogonal matrix which represents rotation operation (exclude mirror operation) or orientation of a right-hand coordinate system.

So it does not have real inverse operation. Here it is just same as transpose operation.

class MATRIX(list) :
    def __init__(self, mat=[], a=None, b=None, c=None, angle=None, axis=None) : # a,b,c are rotations around x,y,z axes
    def __repr__(self) :
    def col(self, idx, arg=[]) : # extraction of column VECTOR
    def row(self, idx, arg=[]) : # extraction of row VECTOR
    def rot_axis(self) : # exraction of rotation angle and axis
    def quaternion(self):  # quaternion for rotation
    def abc(self) : # extraction of alpha, beta, gamma, rotation around x,y,z
    def rpy(self) : # extraction of roll, pitch, yaw, rotation around x,y,z
    def trans(self) : # transposition
    def __neg__(self) : # inverse, ie., transposition
    def __mul__(self, other) : # multiplication with MATRIX or VECTOR
 

generation of MATRIXs (matrices)

generation of a rotation matrix which rotate pi/4 around x-axis.

R1=MATRIX(a=pi/4)
print(R1)
m:[[1.0, 0.0, 0.0], [0.0, 0.7071067811865476, -0.7071067811865475], [0.0, 0.7071067811865475, 0.7071067811865476]]

and rotate pi/6 around y-axis and rotate pi/3 around z-axis

R2=MATRIX(b=pi/6)
R3=MATRIX(c=pi/3)

product of matrices

R123=R1*R2*R3
R123
m:[[0.43301270189221946, -0.75, 0.49999999999999994], [0.7891491309924314, 0.04736717274537666, -0.6123724356957945], [0.4355957403991576, 0.6597396084411711, 0.6123724356957946]]

product of a matrix and a vector, ie. , coordinate transformation or rotation of the vector

R1*VECTOR(0,1,0)
v:[0.0, 0.7071067811865476, 0.7071067811865475]

extraction of abc(alph, beta, gamma Euler angles)

R123.abc()
[0.7853981633974482, 0.5235987755982988, 1.0471975511965976]

extraction of rpy(roll, pitch, yaw Euler angles)

R123.rpy()
[0.8226160330164501, -0.45069999992702, 1.0689453418473993]
(R3*R2*R1).rpy()
[0.7853981633974482, 0.5235987755982988, 1.0471975511965976]

generation of MATRIX with rotation axis and angle (rodrigues)

R4=MATRIX(axis=VECTOR(1,1,0),angle=pi/4)
R4
m:[[0.8535533905932737, 0.14644660940672619, 0.4999999999999999], [0.14644660940672619, 0.8535533905932737, -0.4999999999999999], [-0.4999999999999999, 0.4999999999999999, 0.7071067811865476]]

extraction of rotation axis and angle (rodrigues)

R4.rot_axis()
[0.7853981633974483, v:[0.7071067811865475, 0.7071067811865475, 0.0]]

transpose or inverse of MATRIX

print(R1.trans())
R1*R1.trans()
m:[[1.0, 0.0, 0.0], [0.0, 0.7071067811865476, 0.7071067811865475], [0.0, -0.7071067811865475, 0.7071067811865476]]





m:[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
print(-R1)
R1*(-R1)
m:[[1.0, 0.0, 0.0], [0.0, 0.7071067811865476, 0.7071067811865475], [0.0, -0.7071067811865475, 0.7071067811865476]]





m:[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]
R1.trans().rot_axis()
[0.7853981633974483, v:[-0.9999999999999999, 0.0, 0.0]]

extraction of column and row as a VECTOR

R2.col(0)
v:[0.8660254037844387, 0.0, -0.49999999999999994]
R2.row(0)
v:[0.8660254037844387, 0.0, 0.49999999999999994]

MATRIX to QUATERNION

R1.quaternion()
q:(0.9238795325112867, v:[0.3826834323650897, 0.0, 0.0])

QUATERNION

QUATERNION class has a real part and an imaginary part. The imaginary part is defined as a VECTOR.

Quaternion itself is not only for these operations, it is a kind of number. But QUATERNION here is mainly used for representing rotation operation or orientation of a coordinate system. So only the methods necessary for them are implemented.

class QUATERNION(object) : # quaternion mainly for rotation
    def __init__(self,w_v=None, a=None, b=None, c=None, angle=None, axis=None) : w_v is a list [w,v]
    def __repr__(self) :
    def __mul__(self, other) :
    def __neg__(self) :
    def __abs__(self) :
    def normalize(self) :
    def inv(self) :
    def conjugate(self) :
    def matrix(self) :

generation of QUATERNION

q1 = QUATERNION(a=pi/4)
q1
q:(0.9238795325112867, v:[0.3826834323650898, 0.0, 0.0])
q2 = QUATERNION(b=pi/6)
q3 = QUATERNION(c=pi/3)

generation of QUATERNION with [w, v]

you shouod give arguments as [cos(th/2), sin(th/2)*axis.normalize()]

co=cos((pi/4)/2)
si=sin((pi/4)/2)
q4=QUATERNION([co, si*VECTOR(1,0,0)])
q4
q:(0.9238795325112867, v:[0.3826834323650898, 0.0, 0.0])

generation of QUATERNION with rotation angle and axis

axis does not have to be normalized.

q5=QUATERNION(angle=pi/4, axis=VECTOR(2,0,0))
q5
q:(0.9238795325112867, v:[0.3826834323650898, 0.0, 0.0])

product of QUATERNION

q123=q1*q2*q3

QUATERNION to MATRIX

q123.matrix()
m:[[0.43301270189221946, -0.7500000000000001, 0.5], [0.7891491309924316, 0.04736717274537666, -0.6123724356957946], [0.4355957403991576, 0.6597396084411712, 0.6123724356957947]]
R123
m:[[0.43301270189221946, -0.75, 0.49999999999999994], [0.7891491309924314, 0.04736717274537666, -0.6123724356957945], [0.4355957403991576, 0.6597396084411711, 0.6123724356957946]]

conjugate of QUATERNION, which is inverse of rotational quaternion.

q1*q1.conjugate()
q:(1.0, v:[0.0, 0.0, 0.0])

inverse of QUATERNION

inverse for any QUATERNION

q4=QUATERNION([2,VECTOR(1,2,3)])
q4
q:(2, v:[1.0, 2.0, 3.0])
q4*q4.inv()
q:(4.242640687119286, v:[0.0, 0.0, 0.0])

absolute value and nomalization

abs(q4)
4.242640687119285
q5=q4.normalize()
q4
q:(2, v:[1.0, 2.0, 3.0])
q5
q:(0.47140452079103173, v:[0.23570226039551587, 0.47140452079103173, 0.7071067811865476])

rotattion of vector

q1*QUATERNION([0,VECTOR(0,1,0)])*q1.conjugate()
q:(0.0, v:[0.0, 0.7071067811865475, 0.7071067811865476])

FRAME

FRAME has a MATRIX and a VECTOR which represents orientation and position of coordinate system. It also represets transformation of coordinate system.

class FRAME(object) :
    def __init__(self, frm=[], mat=[], vec=[], xyzabc=[], xyzrpy=[]) :
    def __repr__(self) :
    def xyzabc(self) :
    def xyzrpy(self) :
    def __neg__(self) : # inverse
    def __mul__(self, other) : # multiplication with frame or positional vector
 

generation of FRAME

F1 = FRAME(mat=R123,vec=v1)
F1
f:(m:[[0.43301270189221946, -0.75, 0.49999999999999994], [0.7891491309924314, 0.04736717274537666, -0.6123724356957945], [0.4355957403991576, 0.6597396084411711, 0.6123724356957946]],v:[1.0, 2.0, 3.0])
F2=FRAME(xyzabc=[1,2,3,pi/4,pi/6,pi/3])
F2
f:(m:[[0.43301270189221946, -0.75, 0.49999999999999994], [0.7891491309924314, 0.04736717274537666, -0.6123724356957945], [0.4355957403991576, 0.6597396084411711, 0.6123724356957946]],v:[1.0, 2.0, 3.0])
F3=FRAME(xyzrpy=[1,2,4,pi/4,pi/6,pi/3])
F3
f:(m:[[0.43301270189221946, -0.4355957403991577, 0.7891491309924313], [0.75, 0.6597396084411711, -0.04736717274537655], [-0.49999999999999994, 0.6123724356957945, 0.6123724356957946]],v:[1.0, 2.0, 4.0])

extraction of xyzabc

F1.xyzabc()
[1.0, 2.0, 3.0, 0.7853981633974482, 0.5235987755982988, 1.0471975511965976]
F3.xyzabc()
[1.0, 2.0, 4.0, 0.07719655674229194, 0.9094224366744116, 0.7883719209238913]

extraction of xyzrpy

F1.xyzrpy()
[1.0, 2.0, 3.0, 0.8226160330164501, -0.45069999992702, 1.0689453418473993]
F3.xyzrpy()
[1.0, 2.0, 4.0, 0.7853981633974482, 0.5235987755982988, 1.0471975511965976]

product of frames

product of frames represents the coordinate transformation.

F1*F2
f:(m:[[-0.18656397804474475, -0.03041510175761164, 0.9819718955658528], [0.11234453608956696, -0.9936245501365428, -0.009431785449894092], [0.9759982516925634, 0.10855954564674164, 0.18879151925346918]],v:[1.4330127018922192, 1.0467661693958012, 6.592192264368883])

product of a frame and a vector

product of a frame and a vector represents the coordinate transformation of the position vector.

F1*v2 = R123*v2+v1

F1*v2
v:[-1.25, 2.14210151823613, 4.979218825323513]
R123*v2
v:[-2.25, 0.14210151823613, 1.9792188253235132]
R123*v2+v1
v:[-1.25, 2.14210151823613, 4.979218825323513]