@@ -29,13 +29,16 @@ def __init__(self, arg=None, *, unit='rad'):
29
29
30
30
if arg is None :
31
31
# empty constructor
32
- self .data = [np .eye (2 )]
32
+ if type (self ) is SO2 :
33
+ self .data = [np .eye (2 )]
33
34
34
35
elif argcheck .isvector (arg ):
35
36
# SO2(value)
36
37
# SO2(list of values)
37
38
self .data = [tr .rot2 (x , unit ) for x in argcheck .getvector (arg )]
38
39
40
+ elif isinstance (arg , np .ndarray ) and arg .shape == (2 ,2 ):
41
+ self .data = [arg ]
39
42
else :
40
43
super ().arghandler (arg )
41
44
@@ -44,61 +47,64 @@ def rand(cls, *, range=[0, 2 * math.pi], unit='rad', N=1):
44
47
rand = np .random .uniform (low = range [0 ], high = range [1 ], size = N ) # random values in the range
45
48
return cls ([tr .rot2 (x ) for x in argcheck .getunit (rand , unit )])
46
49
47
- @classmethod
48
- def isvalid (self , x ):
50
+ @staticmethod
51
+ def isvalid (x ):
49
52
return tr .isrot2 (x , check = True )
50
53
51
54
@property
52
55
def T (self ):
53
56
return SO2 (self .A .T )
54
57
58
+ @property
55
59
def inv (self ):
56
- return SO2 (self .A .T )
60
+ if len (self ) == 1 :
61
+ return SO2 (self .A .T )
62
+ else :
63
+ return SO2 ([x .T for x in self .A ])
57
64
58
- # for symmetry with other
59
- @classmethod
60
- def R (cls , theta , unit = 'rad' ):
61
- return SO2 ([tr .rot1 (x , unit ) for x in argcheck .getvector (theta )])
65
+ @property
66
+ def R (self ):
67
+ return self .A [:2 , :2 ]
62
68
63
69
@property
64
- def angle (self ):
70
+ def theta (self ):
65
71
"""Returns angle of SO2 object matrices in unit radians"""
66
- angles = []
67
- for each_matrix in self :
68
- angles .append (math .atan2 (each_matrix [1 , 0 ], each_matrix [0 , 0 ]))
69
- # TODO !! Return list be default ?
70
- if len (angles ) == 1 :
71
- return angles [0 ]
72
- elif len (angles ) > 1 :
73
- return angles
72
+ if len (self ) == 1 :
73
+ return math .atan2 (self .A [1 ,0 ], self .A [0 ,0 ])
74
+ else :
75
+ return [math .atan2 (x .A [1 ,0 ], x .A [0 ,0 ]) for x in self ]
74
76
75
77
76
- class SE2 (sp . SMPose ):
78
+ class SE2 (SO2 ):
77
79
# constructor needs to take ndarray -> SO2, or list of ndarray -> SO2
78
- def __init__ (self , x = None , y = None , theta = 0 , * , unit = 'rad' ):
80
+ def __init__ (self , x = None , y = None , theta = None , * , unit = 'rad' ):
79
81
super ().__init__ () # activate the UserList semantics
80
82
81
- if x is None :
83
+ if x is None and y is None and theta is None :
84
+ # SE2()
82
85
# empty constructor
83
86
self .data = [np .eye (3 )]
84
87
85
- elif all (map (lambda x : isinstance (x , (int , float )), [x , y , theta ])):
86
- # SE2(x, y, theta)
87
- self .data = [tr .trot2 (theta , t = [x , y ], unit = unit )]
88
-
89
- elif argcheck .isvector (x ) and argcheck .isvector (y ) and argcheck .isvector (theta ):
90
- # SE2(xvec, yvec, tvec)
91
- xvec = argcheck .getvector (x )
92
- yvec = argcheck .getvector (y , dim = len (xvec ))
93
- tvec = argcheck .getvector (theta , dim = len (xvec ))
94
- self .data = [tr .trot2 (_t , t = [_x , _y ]) for (_x , _y , _t ) in zip (xvec , yvec , argcheck .getunit (tvec , unit ))]
95
-
96
- elif isinstance (x , np .ndarray ) and y is None and theta is None :
97
- assert x .shape [1 ] == 3 , 'array argument must be Nx3'
98
- self .data = [tr .trot2 (_t , t = [_x , _y ], unit = unit ) for (_x , _y , _t ) in x ]
99
-
88
+ elif x is not None :
89
+ if y is not None and theta is not None :
90
+ # SE2(x, y, theta)
91
+ self .data = [tr .trot2 (theta , t = [x , y ], unit = unit )]
92
+
93
+ elif y is None and theta is None :
94
+ if argcheck .isvector (x , 3 ):
95
+ # SE2( [x,y,theta])
96
+ self .data = [tr .trot2 (x [2 ], t = x [:2 ], unit = unit )]
97
+ elif isinstance (x , np .ndarray ):
98
+ if x .shape == (3 ,3 ):
99
+ # SE2( 3x3 matrix )
100
+ self .data = [x ]
101
+ elif x .shape [1 ] == 3 :
102
+ # SE2( Nx3 )
103
+ self .data = [tr .trot2 (T .theta , t = T .t ) for T in x ]
104
+ else :
105
+ super ().arghandler (x )
100
106
else :
101
- super (). arghandler ( x )
107
+ raise ValueError ( 'bad arguments to constructor' )
102
108
103
109
@property
104
110
def T (self ):
@@ -111,21 +117,27 @@ def rand(cls, *, xrange=[-1, 1], yrange=[-1, 1], trange=[0, 2 * math.pi], unit='
111
117
theta = np .random .uniform (low = trange [0 ], high = trange [1 ], size = N ) # random values in the range
112
118
return cls ([tr .trot2 (t , t = [x , y ]) for (t , x , y ) in zip (x , y , argcheck .getunit (theta , unit ))])
113
119
114
- @classmethod
115
- def isvalid (self , x ):
120
+ @staticmethod
121
+ def isvalid (x ):
116
122
return tr .ishom2 (x , check = True )
117
123
118
124
@property
119
125
def t (self ):
120
126
return self .A [:2 , 2 ]
121
127
122
128
@property
123
- def R (self ):
124
- return SO2 (self .A [:2 , :2 ])
129
+ def xyt (self ):
130
+ if len (self ) == 1 :
131
+ return np .r_ [self .t , self .theta ]
132
+ else :
133
+ return [np .r_ [x .t , x .theta ] for x in self ]
125
134
135
+ @property
126
136
def inv (self ):
127
- return SO2 (self .A .T )
128
- ArithmeticError ()
137
+ if len (self ) == 1 :
138
+ return SE2 (tr .rt2tr (self .R .T , - self .R .T @ self .t ))
139
+ else :
140
+ return SE2 ([tr .rt2tr (x .R .T , - x .R .T @ x .t ) for x in self ])
129
141
130
142
131
143
if __name__ == '__main__' : # pragma: no cover
0 commit comments