1
1
from vpython import shapes , radians , extrusion , vector
2
+ from graphics .graphics_stl import import_object_from_numpy_stl
3
+
2
4
3
5
class Object2D :
4
6
"""
@@ -15,21 +17,114 @@ class Object2D:
15
17
:type colour: `list`
16
18
:raises ValueError: The shape must be in the list of possible shapes
17
19
"""
18
-
19
- # TODO
20
- # Have options to give stl file, shape, or arrow
21
- # Have option to set size, colour, etc
22
- # Have funcs that update pose, texture/colours, visibility
23
-
24
20
def __init__ (self , se2 , scene , shape , colour ):
25
21
# Save inputs
26
- self .__se2 = se2
27
- self .__scene = scene
28
- self .__shape = shape
22
+ self .se2 = se2
23
+ self .scene = scene
24
+ self .shape = shape
25
+ self .size = 0
29
26
if colour [0 ] > 1.0 or colour [1 ] > 1.0 or colour [2 ] > 1.0 or \
30
27
colour [0 ] < 0.0 or colour [1 ] < 0.0 or colour [2 ] < 0.0 :
31
28
raise ValueError ("RGB values must be normalised between 0 and 1" )
32
29
self .__colour = vector (colour [0 ], colour [1 ], colour [2 ])
30
+ self .graphic = None
31
+
32
+ def __create_object (self ):
33
+ """
34
+ To be overridden by child classes
35
+ """
36
+ pass
37
+
38
+ def update_pose (self , new_se2 ):
39
+ """
40
+ Update the pose of the object
41
+
42
+ :param new_se2: The SE2 representation of the pose
43
+ :type new_se2: class:`spatialmath.se2`
44
+ """
45
+ self .se2 = new_se2
46
+ x = self .se2 .t [0 ]
47
+ y = self .se2 .t [1 ]
48
+ t = self .se2 .theta
49
+ self .graphic .pos = vector (x , y , 0 )
50
+ self .graphic .axis = vector (0 , 1 , 0 ).rotate (t )
51
+
52
+ def update_colour (self , colour ):
53
+ """
54
+ Update the colour of the object
55
+
56
+ :param colour: The RGB colour
57
+ :type colour: `list`
58
+ """
59
+ if colour [0 ] > 1.0 or colour [1 ] > 1.0 or colour [2 ] > 1.0 or \
60
+ colour [0 ] < 0.0 or colour [1 ] < 0.0 or colour [2 ] < 0.0 :
61
+ raise ValueError ("RGB values must be normalised between 0 and 1" )
62
+ self .graphic .color = vector (colour [0 ], colour [1 ], colour [2 ])
63
+
64
+ def update_visibility (self , is_visible ):
65
+ """
66
+ Update the visibility of the object
67
+
68
+ :param is_visible: Whether to draw or not
69
+ :type is_visible: `bool`
70
+ """
71
+ self .graphic .visible = is_visible
72
+
73
+ def update_size (self , multiply ):
74
+ """
75
+ Update the size of the object by a multiple of the original size.
76
+
77
+ :param multiply: A number to multiply the original size by
78
+ :type multiply: `float`, `int`
79
+ """
80
+ self .graphic .size = self .size * multiply
81
+
82
+
83
+ class STL2D (Object2D ):
84
+ """
85
+ This object is for 2D objects that contain an STL.
86
+
87
+ :param se2: The SE2 object representing position and orientation
88
+ :type se2: class:`spatialmath.se2`
89
+ :param scene: The scene in which to add the link
90
+ :type scene: class:`vpython.canvas`
91
+ :param stl_path: The file path to the STL to apply
92
+ :type stl_path: `str`
93
+ :param colour: The colour of the shape
94
+ :type colour: `list`
95
+ """
96
+ def __init__ (self , se2 , scene , stl_path , colour ):
97
+ super ().__init__ (se2 , scene , stl_path , colour )
98
+ self .graphic = self .__create_object ()
99
+ self .size = self .graphic .size
100
+ self .graphic .color = self .__colour
101
+
102
+ def __create_object (self ):
103
+ """
104
+ Return a compound of the loaded STL
105
+
106
+ :return: A compound object of the triangles in the STL
107
+ :rtype: class:`vpython.compound`
108
+ """
109
+ return import_object_from_numpy_stl (self .shape , self .scene )
110
+
111
+
112
+ class Marker2D (Object2D ):
113
+ """
114
+ This class will place a marker in the given location based on the given marker inputs
115
+
116
+ :param se2: The SE2 object representing position and orientation
117
+ :type se2: class:`spatialmath.se2`
118
+ :param scene: The scene in which to add the link
119
+ :type scene: class:`vpython.canvas`
120
+ :param shape: The shape of the object
121
+ :type shape: `str`
122
+ :param colour: The colour of the shape
123
+ :type colour: `list`
124
+ :raises ValueError: The shape must be in the list of possible shapes
125
+ """
126
+ def __init__ (self , se2 , scene , shape , colour ):
127
+ super ().__init__ (se2 , scene , shape , colour )
33
128
34
129
self .__marker_size = 0.2
35
130
@@ -54,57 +149,57 @@ def __init__(self, se2, scene, shape, colour):
54
149
raise ValueError ("The shape must be in the list of possible shapes" )
55
150
56
151
# Create the object
57
- self .__graphic = self .__create_object ()
152
+ self .graphic = self .__create_object ()
58
153
59
154
def __create_object (self ):
60
155
"""
61
- Create the physical graphical object
156
+ Create the physical graphical object
62
157
63
- :returns: The graphical entity
64
- :rtype: class:`vpython.baseobj`
65
- """
66
- if self .__shape == '' :
158
+ :returns: The graphical entity
159
+ :rtype: class:`vpython.baseobj`
160
+ """
161
+ if self .shape == '' :
67
162
# 2D coords of the circle boundary
68
- shape_path = shapes .circle (radius = self .__marker_size / 2 )
69
- elif self .__shape == '+' :
163
+ shape_path = shapes .circle (radius = self .__marker_size / 2 )
164
+ elif self .shape == '+' :
70
165
# 2D coords of the cross boundary
71
- shape_path = shapes .cross (width = self .__marker_size , thickness = self .__marker_size / 5 )
72
- elif self .__shape == 'o' :
166
+ shape_path = shapes .cross (width = self .__marker_size , thickness = self .__marker_size / 5 )
167
+ elif self .shape == 'o' :
73
168
# 2D coords of the circle boundary
74
- shape_path = shapes .circle (radius = self .__marker_size / 2 )
75
- elif self .__shape == '*' :
169
+ shape_path = shapes .circle (radius = self .__marker_size / 2 )
170
+ elif self .shape == '*' :
76
171
# 2D coords of the star boundary
77
- shape_path = shapes .star (radius = self .__marker_size / 2 , n = 6 )
78
- elif self .__shape == '.' :
172
+ shape_path = shapes .star (radius = self .__marker_size / 2 , n = 6 )
173
+ elif self .shape == '.' :
79
174
# 2D coords of the square boundary
80
175
shape_path = shapes .rectangle (width = self .__marker_size , height = self .__marker_size )
81
- elif self .__shape == 'x' :
176
+ elif self .shape == 'x' :
82
177
# 2D coords of the cross boundary
83
- shape_path = shapes .cross (width = self .__marker_size , thickness = self .__marker_size / 5 , rotate = radians (45 ))
84
- elif self .__shape == 's' :
178
+ shape_path = shapes .cross (width = self .__marker_size , thickness = self .__marker_size / 5 , rotate = radians (45 ))
179
+ elif self .shape == 's' :
85
180
# 2D coords of the square boundary
86
181
shape_path = shapes .rectangle (width = self .__marker_size , height = self .__marker_size ,
87
182
thickness = self .__marker_size )
88
- elif self .__shape == 'd' :
183
+ elif self .shape == 'd' :
89
184
# 2D coords of the diamond boundary
90
185
shape_path = shapes .rectangle (width = self .__marker_size , height = self .__marker_size ,
91
186
thickness = self .__marker_size , rotate = radians (45 ))
92
- elif self .__shape == '^' :
187
+ elif self .shape == '^' :
93
188
# 2D coords of the triangle boundary
94
189
shape_path = shapes .triangle (length = self .__marker_size )
95
- elif self .__shape == 'v' :
190
+ elif self .shape == 'v' :
96
191
# 2D coords of the triangle boundary
97
192
shape_path = shapes .triangle (length = self .__marker_size , rotate = radians (180 ))
98
- elif self .__shape == '<' :
193
+ elif self .shape == '<' :
99
194
# 2D coords of the triangle boundary
100
195
shape_path = shapes .triangle (length = self .__marker_size , rotate = radians (90 ))
101
- elif self .__shape == '>' :
196
+ elif self .shape == '>' :
102
197
# 2D coords of the triangle boundary
103
198
shape_path = shapes .triangle (length = self .__marker_size , rotate = radians (- 90 ))
104
- elif self .__shape == 'p' :
199
+ elif self .shape == 'p' :
105
200
# 2D coords of the pentagon boundary
106
201
shape_path = shapes .pentagon (length = self .__marker_size )
107
- elif self .__shape == 'h' :
202
+ elif self .shape == 'h' :
108
203
# 2D coords of the hexagon boundary
109
204
shape_path = shapes .hexagon (length = self .__marker_size )
110
205
# CURRENTLY UNUSED
@@ -118,13 +213,14 @@ def __create_object(self):
118
213
raise ValueError ("Invalid shape given" )
119
214
120
215
# Create the shape
121
- x = self .__se2 .t [0 ]
122
- y = self .__se2 .t [1 ]
123
- obj = extrusion (scene = self .__scene ,
216
+ x = self .se2 .t [0 ]
217
+ y = self .se2 .t [1 ]
218
+ obj = extrusion (scene = self .scene ,
124
219
path = [vector (x , y , 0.001 ), vector (x , y , - 0.001 )],
125
220
shape = shape_path ,
126
221
color = self .__colour ,
127
222
shininess = 0 )
128
- if self .__shape == '' :
223
+ self .size = obj .size
224
+ if self .shape == '' :
129
225
obj .visible = False
130
226
return obj
0 commit comments