Skip to content

Commit 805b59b

Browse files
committed
Bug fix error reporting on curve.pts(N) out of range
1 parent 54d9ab9 commit 805b59b

File tree

1 file changed

+28
-91
lines changed

1 file changed

+28
-91
lines changed

vpython/vpython.py

Lines changed: 28 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import sys
1414
from . import __version__, __gs_version__
1515
from ._notebook_helpers import _isnotebook
16-
from ._vector_import_helper import (vector, mag, norm, cross, dot, adjust_up,
16+
from ._vector_import_helper import (vector, mag, norm, dot, adjust_up,
1717
adjust_axis, object_rotate)
1818

1919
# List of names that will be imported from this file with import *
@@ -97,7 +97,7 @@
9797
'right':'q', 'top':'r', 'bottom':'s', '_cloneid':'t',
9898
'logx':'u', 'logy':'v', 'dot':'w', 'dot_radius':'x',
9999
'markers':'y', 'legend':'z', 'label':'A', 'delta':'B', 'marker_color':'C',
100-
'size_units':'D', 'userpan':'E', 'scroll':'F', 'choices':'G', 'depth':'H'}
100+
'size_units':'D', 'userpan':'E', 'scroll':'F'}
101101

102102
# methods are X in {'m': '23X....'}
103103
# pos is normally updated as an attribute, but for interval-based trails, it is updated (multiply) as a method
@@ -113,7 +113,7 @@
113113
'marker_color']
114114

115115
__textattrs = ['text', 'align', 'caption', 'title', 'xtitle', 'ytitle', 'selected', 'label', 'capture',
116-
'append_to_caption', 'append_to_title', 'bind', 'unbind', 'pause', 'GSprint', 'choices']
116+
'append_to_caption', 'append_to_title', 'bind', 'unbind', 'pause', 'GSprint']
117117

118118
def _encode_attr2(sendval, val, ismethods):
119119
s = ''
@@ -129,10 +129,8 @@ def _encode_attr2(sendval, val, ismethods):
129129
s += "{:.16G},".format(p)
130130
s = s[:-1]
131131
elif sendval == 'plot' or sendval == 'data':
132-
if sendval == 'data' and len(val) == 0: s += "None, None,"
133-
else:
134-
for p in val:
135-
s += "{:.16G},{:.16G},".format(p[0], p[1])
132+
for p in val:
133+
s += "{:.16G},{:.16G},".format(p[0], p[1])
136134
s = s[:-1]
137135
elif sendval in ['v0', 'v1', 'v2', 'v3']: # val is the vertex object referenced by triangle or quad
138136
s += str(val.idx)
@@ -330,10 +328,10 @@ def __del__(self):
330328
# Now there is no threading in Jupyter VPython. Data is sent to the
331329
# browser from the trigger() function, which is called by a
332330
# canvas_update event sent to Python from the browser (glowcomm.js), currently
333-
# every 17 milliseconds. When trigger() is called, it immediately signals
334-
# the browser to set a timeout of 17 ms to send another signal to Python.
331+
# every 33 milliseconds. When trigger() is called, it immediately signals
332+
# the browser to set a timeout of 33 ms to send another signal to Python.
335333
# Note that a typical VPython program starts out by creating objects (constructors) and
336-
# specifying their attributes. The 17 ms signal from the browser is adequate to ensure
334+
# specifying their attributes. The 33 ms signal from the browser is adequate to ensure
337335
# prompt data transmissions to the browser.
338336

339337
# The situation with non-notebook use is similar, but the http server is threaded,
@@ -402,10 +400,9 @@ def handle_close(self, data):
402400
def _wait(cvs): # wait for an event
403401
cvs._waitfor = None
404402
if _isnotebook: baseObj.trigger() # in notebook environment must send methods immediately
405-
t = clock()
406403
while cvs._waitfor is None:
407-
rate(100)
408-
if _isnotebook: baseObj.trigger() # restart activity in glowcomm.html
404+
rate(30)
405+
return cvs._waitfor
409406

410407
class color(object):
411408
black = vector(0,0,0)
@@ -587,7 +584,6 @@ def setup(self, args):
587584
del args['_objName']
588585

589586
# default values
590-
self._sizing = True # axis/size connection is the default; False for sphere, ring, text, compound
591587
self._pos = vector(0,0,0)
592588
self._axis = vector(1,0,0)
593589
self._up = vector(0,1,0)
@@ -764,52 +760,32 @@ def up(self,value):
764760
def axis(self):
765761
return self._axis
766762
@axis.setter
767-
def axis(self,value): # sphere or ring or text or compound have no axis/size link
768-
currentaxis = self._axis
769-
self._axis = value
770-
if value.mag2 == 0:
771-
if self._save_oldaxis is None: self._save_oldaxis = currentaxis
772-
else:
773-
if self._save_oldaxis is not None:
774-
self._save_oldaxis = adjust_up(self._axis, value, self._up, self._save_oldaxis) # this sets self._axis and self._up
763+
def axis(self,value):
764+
self._save_oldaxis = adjust_up(self._axis, value, self._up, self._save_oldaxis) # this sets self._axis and self._up
775765
if not self._constructing:
776766
self.addattr('axis')
777-
if self._sizing:
778-
self._size._x = value.mag # changing axis length changes size.x
767+
self._size._x = value.mag # changing axis length changes size.x
779768

780769
@property
781770
def size(self):
782771
return self._size
783772
@size.setter
784-
def size(self,value): # sphere or ring or text or compound have no axis/size link
785-
currentaxis = self._axis
786-
self._size = value
787-
if value.x == 0:
788-
if self._save_oldaxis is not None:
789-
currentaxis = self._save_oldaxis
790-
self._save_oldaxis = None
791-
else:
792-
currentaxis = vector(1,0,0)
773+
def size(self,value):
774+
self._size.value = value
793775
if not self._constructing:
794776
self.addattr('size')
795-
if self._sizing:
796-
self._axis = currentaxis.norm()*value.x
777+
a = self._axis.norm() * value.x
778+
if mag(self._axis) == 0:
779+
a = vector(value.x,0,0)
780+
self._axis.value = a # changing size changes length of axis
797781

798782
@property
799783
def length(self):
800784
return self._size.x
801785
@length.setter
802786
def length(self,value):
803-
if value == 0:
804-
if self._save_oldaxis is None: self._save_oldaxis = vector(self._axis.x, self._axis.y, self._axis.z)
805-
self._axis = vector(0,0,0)
806-
self._size._x = 0
807-
else:
808-
if self._save_oldaxis is not None:
809-
self._axis = self._save_oldaxis
810-
self._save_oldaxis = None
811-
if self._size._x == 0: self.axis = vector(value, 0, 0)
812-
else: self.axis = value*self._axis.norm() # this will set length
787+
self._axis = self._axis.norm() * value
788+
self._size._x = value
813789
if not self._constructing:
814790
self.addattr('axis')
815791
self.addattr('size')
@@ -1039,24 +1015,6 @@ def rotate(self, angle=None, axis=None, origin=None):
10391015
self._pos.value = newpos
10401016
self.addattr('pos')
10411017

1042-
def bounding_box(self):
1043-
centered = ['box', 'compound', 'ellipsoid', 'sphere', 'simple_sphere', 'ring']
1044-
x = norm(self._axis)
1045-
y = norm(self._up)
1046-
z = norm(cross(x,y))
1047-
L = self._size.x
1048-
H = self._size.y
1049-
W = self._size.z
1050-
p = vector(self._pos) # make a copy of pos, so changes to p won't affect the object
1051-
if self._objName not in centered:
1052-
p = p + 0.5*L*x # move to center
1053-
pts = []
1054-
for dx in [-L/2, L/2]:
1055-
for dy in [-H/2, H/2]:
1056-
for dz in [-W/2, W/2]:
1057-
pts.append(p + dx*x + dy*y + dz*z)
1058-
return pts
1059-
10601018
def _on_size_change(self): # the vector class calls this when there's a change in x, y, or z
10611019
self._axis.value = self._axis.norm() * self._size.x # update axis length when box.size.x is changed
10621020
self.addattr('size')
@@ -1145,7 +1103,6 @@ def __init__(self, **args):
11451103
args['_default_size'] = vector(2,2,2)
11461104
args['_objName'] = "sphere"
11471105
super(sphere, self).setup(args)
1148-
self._sizing = False # no axis/size connection
11491106

11501107
@property
11511108
def radius(self):
@@ -1236,7 +1193,6 @@ def __init__(self, **args):
12361193
args['_default_size'] = vector(0.2,2.2,2.2)
12371194
args['_objName'] = "ring"
12381195
super(ring, self).setup(args)
1239-
self._sizing = False # no axis/size connection
12401196

12411197
@property
12421198
def thickness(self):
@@ -1492,7 +1448,6 @@ def __init__(self, objList, **args):
14921448
self.compound_idx += 1
14931449
args['_objName'] = 'compound'+str(self.compound_idx)
14941450
super(compound, self).setup(args)
1495-
self._sizing = False # no axis/size connection
14961451

14971452
for obj in objList:
14981453
# GlowScript will make the objects invisible, so need not set obj.visible
@@ -1856,8 +1811,8 @@ def pop(self, *args):
18561811
return val
18571812

18581813
def point(self,N):
1859-
if N >= len(self._pts) or (N < 0 and -N >= len(self.pts)):
1860-
raise ValueError('N = {} is outside the bounds 0-{} of the curve points'.format(N, len(self._pos)))
1814+
if N >= len(self._pts) or (N < 0 and -N > len(self._pts)):
1815+
raise ValueError('N = {} is outside the bounds 0-{} of the curve points'.format(N, len(self._pts)-1))
18611816
info = self._pts[N]
18621817
if 'color' not in info: info['color'] = self.color
18631818
if 'radius' not in info: info['radius'] = self.radius
@@ -2026,8 +1981,6 @@ def setup(self, args):
20261981
self._legend = False
20271982
self._interval = -1
20281983
self._graph = None
2029-
self._visible = True
2030-
self._data = []
20311984
objName = args['_objName']
20321985
del args['_objName']
20331986
self._constructing = True ## calls are from constructor
@@ -2163,8 +2116,6 @@ def preresolve2(self, args):
21632116
raise AttributeError("Cannot currently change color in a plot statement.")
21642117
if 'pos' in args:
21652118
return self.resolveargs(args['pos'])
2166-
elif 'data' in args:
2167-
return self.resolveargs(args['data'])
21682119
else:
21692120
raise AttributeError("Must be plot(x,y) or plot(pos=[x,y]) or plot([x,y]) or plot([x,y], ...) or plot([ [x,y], ... ])")
21702121

@@ -2173,18 +2124,8 @@ def plot(self, *args1, **args2):
21732124
p = self.preresolve1(args1)
21742125
else:
21752126
p = self.preresolve2(args2)
2176-
self._data = self._data + p
21772127
self.addmethod('plot', p)
21782128

2179-
@property
2180-
def visible(self):
2181-
return self._visible
2182-
@visible.setter
2183-
def visible(self,value):
2184-
self._visible = value
2185-
if not self._constructing:
2186-
self.addattr('visible')
2187-
21882129
def delete(self):
21892130
self.addmethod('delete', 'None')
21902131

@@ -2881,8 +2822,7 @@ def __init__(self, **args):
28812822
baseObj._canvas_constructing = False
28822823

28832824
def follow(self, obj): ## should allow a function also
2884-
if obj is None: self.addmethod('follow', 'None')
2885-
else: self.addmethod('follow', obj.idx)
2825+
self.addmethod('follow', obj.idx)
28862826

28872827
def select(self):
28882828
canvas.selected = self
@@ -3369,7 +3309,6 @@ class controls(baseObj):
33693309
def setup(self, args):
33703310
super(controls, self).__init__() ## get idx, attrsupdt from baseObj
33713311
## default values of common attributes
3372-
self._disabled = False
33733312
self._constructing = True
33743313
argsToSend = []
33753314
objName = args['_objName']
@@ -3604,8 +3543,7 @@ def choices(self):
36043543
return self._choices
36053544
@choices.setter
36063545
def choices(self, value):
3607-
self._choices = value
3608-
self.addattr('choices')
3546+
raise AttributeError('choices cannot be modified after a menu is created')
36093547

36103548
@property
36113549
def index(self):
@@ -3889,7 +3827,6 @@ def end_face_color(self,value):
38893827
class text(standardAttributes):
38903828

38913829
def __init__(self, **args):
3892-
self._sizing = False # no axis/size connection
38933830
args['_default_size'] = vector(1,1,1) # to keep standardAttributes happy
38943831
args['_objName'] = "text"
38953832
self._height = 1 ## not derived from size
@@ -3944,10 +3881,10 @@ def axis(self):
39443881
return self._axis
39453882
@axis.setter
39463883
def axis(self,value): # changing axis does not affect size
3947-
old = vector(self.axis)
3884+
oldaxis = vector(self.axis)
39483885
u = self.up
39493886
self._axis.value = value
3950-
self._save_oldaxis = adjust_up(norm(old), self._axis, self._up, self._save_oldaxis)
3887+
self._save_oldaxis = adjust_up(norm(oldaxis), self._axis, self._up, self._save_oldaxis)
39513888
self.addattr('axis')
39523889
self.addattr('up')
39533890

@@ -3985,7 +3922,7 @@ def depth(self, val): # sign issue ??
39853922
if abs(val) < 0.01*self._height:
39863923
if val < 0: val = -0.01*self._height
39873924
else: val = 0.01*self._height
3988-
self._depth = val
3925+
self._depth = value
39893926
self.addattr('depth')
39903927

39913928
@property

0 commit comments

Comments
 (0)