1
1
from vpython import vector , compound , mag , box
2
- from numpy import sign , ceil
2
+ from numpy import sign , ceil , arange
3
3
from graphics .graphics_text import update_grid_numbers
4
4
from graphics .graphics_object2d import Marker2D
5
5
from spatialmath import SE2
@@ -21,6 +21,7 @@ def __init__(self, scene):
21
21
22
22
self .__relative_cam = True
23
23
self .__num_squares = 10
24
+ self .__scale = 1
24
25
25
26
# Save the current camera settings
26
27
self .camera_pos = self .__scene .camera .pos
@@ -56,7 +57,8 @@ def __init_grid(self):
56
57
self .grid_object [self .__planes_idx ] = the_grid
57
58
58
59
# Update the labels instead of recreating them
59
- update_grid_numbers (self .__focal_point , self .grid_object [self .__labels_idx ], self .__num_squares , self .__scene )
60
+ update_grid_numbers (self .__focal_point , self .grid_object [self .__labels_idx ],
61
+ self .__num_squares , self .__scale , self .__is_3d , self .__scene )
60
62
61
63
def __create_grid_objects (self ):
62
64
"""
@@ -73,10 +75,17 @@ def __create_grid_objects(self):
73
75
camera_axes = self .camera_axes
74
76
# Locate centre of axes
75
77
if self .__relative_cam :
76
- x_origin , y_origin , z_origin = round (self .__scene .center .x ), \
77
- round (self .__scene .center .y ), \
78
- round (self .__scene .center .z )
78
+ x_origin , y_origin , z_origin = round (self .__scene .center .x , 2 ), \
79
+ round (self .__scene .center .y , 2 ), \
80
+ round (self .__scene .center .z , 2 )
79
81
self .__focal_point = [x_origin , y_origin , z_origin ]
82
+ # Convert focal point for 2D rendering. Puts focus point in centre of the view
83
+ if not self .__is_3d :
84
+ self .__focal_point = [val - int (self .__num_squares / 2 ) for val in self .__focal_point ]
85
+ x_origin = self .__focal_point [0 ]
86
+ y_origin = self .__focal_point [1 ]
87
+ z_origin = 0
88
+ self .__focal_point [2 ] = z_origin
80
89
else :
81
90
x_origin , y_origin , z_origin = self .__focal_point [0 ], \
82
91
self .__focal_point [1 ], \
@@ -96,67 +105,104 @@ def __create_grid_objects(self):
96
105
# min = -num_squares or 0, around the default position
97
106
# max = +num_squares or 0, around the default position
98
107
# e.g. at the origin, for negative axes: -10 -> 0, positive axes: 0 -> 10
99
- min_x_coord = x_origin + int (- (self .__num_squares / 2 ) + (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 ))
100
- max_x_coord = x_origin + int ((self .__num_squares / 2 ) + (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 ))
108
+ min_x_coord = round (x_origin + (- (self .__num_squares / 2 ) +
109
+ (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
110
+ max_x_coord = round (x_origin + ((self .__num_squares / 2 ) +
111
+ (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
112
+
113
+ min_y_coord = round (y_origin + (- (self .__num_squares / 2 ) +
114
+ (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
115
+ max_y_coord = round (y_origin + ((self .__num_squares / 2 ) +
116
+ (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
117
+
118
+ min_z_coord = round (z_origin + (- (self .__num_squares / 2 ) +
119
+ (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
120
+ max_z_coord = round (z_origin + ((self .__num_squares / 2 ) +
121
+ (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
101
122
102
- min_y_coord = y_origin + int (- (self .__num_squares / 2 ) + (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 ))
103
- max_y_coord = y_origin + int ((self .__num_squares / 2 ) + (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 ))
123
+ x_coords = arange (min_x_coord , max_x_coord + self .__scale , self .__scale )
124
+ y_coords = arange (min_y_coord , max_y_coord + self .__scale , self .__scale )
125
+ z_coords = arange (min_z_coord , max_z_coord + self .__scale , self .__scale )
104
126
105
- min_z_coord = z_origin + int (- (self .__num_squares / 2 ) + (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 ))
106
- max_z_coord = z_origin + int ((self .__num_squares / 2 ) + (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 ))
127
+ # Compound origins are in the middle of the bounding boxes. Thus new pos will be between max and min.
128
+ x_middle = (max_x_coord + min_x_coord ) / 2
129
+ y_middle = (max_y_coord + min_y_coord ) / 2
130
+ z_middle = (max_z_coord + min_z_coord ) / 2
131
+
132
+ line_thickness = min (max (self .__scale / 25 , 0.01 ), 5 ) # 0.01 -> 5
107
133
108
134
# XZ plane
109
- for x_point in range ( min_x_coord , max_x_coord + 1 ) :
135
+ for x_point in x_coords :
110
136
# Draw a line across for each x coord, along the same y-axis, from min to max z coord
111
137
xz_lines .append (create_line (
112
138
vector (x_point , y_origin , min_z_coord ),
113
139
vector (x_point , y_origin , max_z_coord ),
114
- self .__scene
140
+ self .__scene ,
141
+ thickness = line_thickness
115
142
))
116
- for z_point in range ( min_z_coord , max_z_coord + 1 ) :
143
+ for z_point in z_coords :
117
144
# Draw a line across each z coord, along the same y-axis, from min to max z coord
118
145
xz_lines .append (create_line (
119
146
vector (min_x_coord , y_origin , z_point ),
120
147
vector (max_x_coord , y_origin , z_point ),
121
- self .__scene
148
+ self .__scene ,
149
+ thickness = line_thickness
122
150
))
123
151
124
152
# XY plane
125
- for x_point in range ( min_x_coord , max_x_coord + 1 ) :
153
+ for x_point in x_coords :
126
154
# Draw a line across each x coord, along the same z-axis, from min to max y coord
127
155
xy_lines .append (create_line (
128
156
vector (x_point , min_y_coord , z_origin ),
129
157
vector (x_point , max_y_coord , z_origin ),
130
- self .__scene
158
+ self .__scene ,
159
+ thickness = line_thickness
131
160
))
132
- for y_point in range ( min_y_coord , max_y_coord + 1 ) :
161
+ for y_point in y_coords :
133
162
# Draw a line across each y coord, along the same z-axis, from min to max x coord
134
163
xy_lines .append (create_line (
135
164
vector (min_x_coord , y_point , z_origin ),
136
165
vector (max_x_coord , y_point , z_origin ),
137
- self .__scene
166
+ self .__scene ,
167
+ thickness = line_thickness
138
168
))
139
169
140
170
# YZ plane
141
- for y_point in range ( min_y_coord , max_y_coord + 1 ) :
171
+ for y_point in y_coords :
142
172
# Draw a line across each y coord, along the same x-axis, from min to max z coord
143
173
yz_lines .append (create_line (
144
174
vector (x_origin , y_point , min_z_coord ),
145
175
vector (x_origin , y_point , max_z_coord ),
146
- self .__scene
176
+ self .__scene ,
177
+ thickness = line_thickness
147
178
))
148
- for z_point in range ( min_z_coord , max_z_coord + 1 ) :
179
+ for z_point in z_coords :
149
180
# Draw a line across each z coord, along the same x-axis, from min to max y coord
150
181
yz_lines .append (create_line (
151
182
vector (x_origin , min_y_coord , z_point ),
152
183
vector (x_origin , max_y_coord , z_point ),
153
- self .__scene
184
+ self .__scene ,
185
+ thickness = line_thickness
154
186
))
155
187
156
188
# Compound the lines together into respective objects
157
- xz_plane = compound (xz_lines )
158
- xy_plane = compound (xy_lines )
159
- yz_plane = compound (yz_lines )
189
+ # XY Plane
190
+ if camera_axes .z < 0 :
191
+ xy_plane = compound (xy_lines , origin = vector (x_middle , y_middle , min_z_coord ))
192
+ else :
193
+ xy_plane = compound (xy_lines , origin = vector (x_middle , y_middle , max_z_coord ))
194
+
195
+ # XZ Plane
196
+ if camera_axes .y < 0 :
197
+ xz_plane = compound (xz_lines , origin = vector (x_middle , min_y_coord , z_middle ))
198
+ else :
199
+ xz_plane = compound (xz_lines , origin = vector (x_middle , max_y_coord , z_middle ))
200
+
201
+ # YZ Plane
202
+ if camera_axes .x < 0 :
203
+ yz_plane = compound (yz_lines , origin = vector (min_x_coord , y_middle , z_middle ))
204
+ else :
205
+ yz_plane = compound (yz_lines , origin = vector (max_x_coord , y_middle , z_middle ))
160
206
161
207
# Combine all into one list
162
208
grid = [None , None , None ]
@@ -173,9 +219,9 @@ def __move_grid_objects(self):
173
219
camera_axes = self .camera_axes
174
220
# Locate centre of axes
175
221
if self .__relative_cam :
176
- x_origin , y_origin , z_origin = round (self .__scene .center .x ), \
177
- round (self .__scene .center .y ), \
178
- round (self .__scene .center .z )
222
+ x_origin , y_origin , z_origin = round (self .__scene .center .x , 2 ), \
223
+ round (self .__scene .center .y , 2 ), \
224
+ round (self .__scene .center .z , 2 )
179
225
self .__focal_point = [x_origin , y_origin , z_origin ]
180
226
# Convert focal point for 2D rendering. Puts focus point in centre of the view
181
227
if not self .__is_3d :
@@ -203,14 +249,20 @@ def __move_grid_objects(self):
203
249
# min = -num_squares or 0, around the default position
204
250
# max = +num_squares or 0, around the default position
205
251
# e.g. at the origin, for negative axes: -10 -> 0, positive axes: 0 -> 10
206
- min_x_coord = x_origin + int (- (self .__num_squares / 2 ) + (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 ))
207
- max_x_coord = x_origin + int ((self .__num_squares / 2 ) + (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 ))
252
+ min_x_coord = round (x_origin + (- (self .__num_squares / 2 ) +
253
+ (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
254
+ max_x_coord = round (x_origin + ((self .__num_squares / 2 ) +
255
+ (sign (camera_axes .x ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
208
256
209
- min_y_coord = y_origin + int (- (self .__num_squares / 2 ) + (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 ))
210
- max_y_coord = y_origin + int ((self .__num_squares / 2 ) + (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 ))
257
+ min_y_coord = round (y_origin + (- (self .__num_squares / 2 ) +
258
+ (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
259
+ max_y_coord = round (y_origin + ((self .__num_squares / 2 ) +
260
+ (sign (camera_axes .y ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
211
261
212
- min_z_coord = z_origin + int (- (self .__num_squares / 2 ) + (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 ))
213
- max_z_coord = z_origin + int ((self .__num_squares / 2 ) + (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 ))
262
+ min_z_coord = round (z_origin + (- (self .__num_squares / 2 ) +
263
+ (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
264
+ max_z_coord = round (z_origin + ((self .__num_squares / 2 ) +
265
+ (sign (camera_axes .z ) * - 1 ) * (self .__num_squares / 2 )) * self .__scale , 2 )
214
266
215
267
# Compound origins are in the middle of the bounding boxes. Thus new pos will be between max and min.
216
268
x_middle = (max_x_coord + min_x_coord ) / 2
@@ -240,23 +292,30 @@ def update_grid(self):
240
292
Update the grid axes and numbers if the camera position/rotation has changed.
241
293
"""
242
294
# Obtain the new camera settings
243
- new_camera_pos = self .__scene .camera .pos
244
- new_camera_axes = self .__scene .camera .axis
295
+ new_camera_pos = vector (self .__scene .camera .pos )
296
+ new_camera_axes = vector (self .__scene .camera .axis )
297
+
298
+ old_camera_pos = vector (self .camera_pos )
299
+ old_camera_axes = vector (self .camera_axes )
300
+
301
+ # Update old positions
302
+ self .camera_pos = new_camera_pos
303
+ self .camera_axes = new_camera_axes
245
304
246
- old_camera_pos = self .camera_pos
247
- old_camera_axes = self .camera_axes
305
+ distance_from_center = mag (self .__scene .center - self .__scene .camera .pos )
306
+ new_scale = round (distance_from_center / 30.0 , 1 )
307
+ if not new_scale == self .__scale :
308
+ self .set_scale (new_scale )
248
309
249
310
# If camera is different to previous: update
250
311
if (not new_camera_axes .equals (old_camera_axes )) or (not new_camera_pos .equals (old_camera_pos )):
251
- # Update old positions
252
- self .camera_pos = new_camera_pos
253
- self .camera_axes = new_camera_axes
254
-
255
312
# Update grid
256
313
self .__move_grid_objects ()
257
314
update_grid_numbers (self .__focal_point ,
258
315
self .grid_object [self .__labels_idx ],
259
316
self .__num_squares ,
317
+ self .__scale ,
318
+ self .__is_3d ,
260
319
self .__scene )
261
320
262
321
def toggle_2d_3d (self ):
@@ -312,6 +371,24 @@ def set_relative(self, is_relative):
312
371
self .__relative_cam = is_relative
313
372
self .update_grid ()
314
373
374
+ def set_scale (self , value ):
375
+ """
376
+ Set the scale and redraw the grid
377
+
378
+ :param value: The value to set the scale to
379
+ :type value: `float`
380
+ """
381
+ value = max (min (value , 100 ), 0.1 ) # Between 0.1 and 100
382
+ self .__scale = value
383
+ # Turn off grid then delete
384
+ for plane in self .grid_object [self .__planes_idx ]:
385
+ plane .visible = False
386
+ for text in self .grid_object [self .__labels_idx ]:
387
+ text .visible = False
388
+
389
+ self .grid_object = [[], []]
390
+ self .__init_grid ()
391
+
315
392
316
393
def create_line (pos1 , pos2 , scene , colour = None , thickness = 0.01 ):
317
394
"""
@@ -338,14 +415,14 @@ def create_line(pos1, pos2, scene, colour=None, thickness=0.01):
338
415
colour = [0 , 0 , 0 ]
339
416
340
417
if colour [0 ] > 1.0 or colour [1 ] > 1.0 or colour [2 ] > 1.0 or \
341
- colour [0 ] < 0.0 or colour [1 ] < 0.0 or colour [2 ] < 0.0 :
418
+ colour [0 ] < 0.0 or colour [1 ] < 0.0 or colour [2 ] < 0.0 :
342
419
raise ValueError ("RGB values must be normalised between 0 and 1" )
343
420
344
421
if thickness < 0.0 :
345
422
raise ValueError ("Thickness must be greater than 0" )
346
423
347
424
# Length of the line using the magnitude
348
- line_len = mag (pos2 - pos1 )
425
+ line_len = mag (pos2 - pos1 )
349
426
350
427
# Position of the line is the midpoint (centre) between the ends
351
428
position = (pos1 + pos2 ) / 2
@@ -391,14 +468,14 @@ def create_segmented_line(pos1, pos2, scene, segment_len, colour=None, thickness
391
468
colour = [0 , 0 , 0 ]
392
469
393
470
if colour [0 ] > 1.0 or colour [1 ] > 1.0 or colour [2 ] > 1.0 or \
394
- colour [0 ] < 0.0 or colour [1 ] < 0.0 or colour [2 ] < 0.0 :
471
+ colour [0 ] < 0.0 or colour [1 ] < 0.0 or colour [2 ] < 0.0 :
395
472
raise ValueError ("RGB values must be normalised between 0 and 1" )
396
473
397
474
if thickness < 0.0 :
398
475
raise ValueError ("Thickness must be greater than 0" )
399
476
400
477
# Length of the line using the magnitude
401
- line_len = mag (pos2 - pos1 )
478
+ line_len = mag (pos2 - pos1 )
402
479
403
480
# Axis direction of the line (to align the box (line) to intersect the two points)
404
481
axis_dir = pos2 - pos1
@@ -407,24 +484,24 @@ def create_segmented_line(pos1, pos2, scene, segment_len, colour=None, thickness
407
484
# Return a compound of boxes of thin width and height to resemble a dashed line
408
485
dash_positions = []
409
486
boxes = []
410
- pos1 = pos1 + (axis_dir * segment_len / 2 ) # Translate centre pos to centre of where dashes will originate from
487
+ pos1 = pos1 + (axis_dir * segment_len / 2 ) # Translate centre pos to centre of where dashes will originate from
411
488
412
489
# Range = number of dashes (vis and invis)
413
- for idx in range (0 , int (ceil (line_len / (segment_len / axis_dir .mag )))):
490
+ for idx in range (0 , int (ceil (line_len / (segment_len / axis_dir .mag )))):
414
491
# Add every even point (zeroth, second...) to skip gaps between boxes
415
492
if idx % 2 == 0 :
416
493
dash_positions .append (pos1 )
417
494
pos1 = (pos1 + axis_dir * segment_len )
418
495
# If the axis between points changes, then the line has surpassed the end point. The line is done
419
- check_dir = pos2 - pos1
496
+ check_dir = pos2 - pos1
420
497
check_dir .mag = 1.0
421
498
if not vectors_approx_equal (axis_dir , check_dir ):
422
499
break
423
500
424
501
for xyz in dash_positions :
425
502
length = segment_len
426
503
# If the box will surpass the end point
427
- len_to_end = (pos2 - xyz ).mag
504
+ len_to_end = (pos2 - xyz ).mag
428
505
if len_to_end < segment_len / 2 :
429
506
# Length is equal to dist to the end * 2 (as pos is middle of box)
430
507
length = len_to_end * 2
0 commit comments