1313import sys
1414from . import __version__ , __gs_version__
1515from ._notebook_helpers import _isnotebook
16- from ._vector_import_helper import (vector , mag , norm , dot , adjust_up ,
16+ from ._vector_import_helper import (vector , mag , norm , cross , dot , adjust_up ,
1717 adjust_axis , object_rotate )
1818
1919# List of names that will be imported from this file with import *
2828 'standardAttributes' , 'text' , 'textures' , 'triangle' , 'vertex' ,
2929 'wtext' , 'winput' , 'keysdown' ]
3030
31- from inspect import signature # needed to allow zero arguments in a bound function
31+ __p = platform .python_version ()
32+ _ispython3 = (__p [0 ] == '3' )
33+
34+ if _ispython3 :
35+ from inspect import signature # Python 3; needed to allow zero arguments in a bound function
36+ else :
37+ from inspect import getargspec # Python 2; needed to allow zero arguments in a bound function
3238
3339# __version__ is the version number of the Jupyter VPython installer, generated in building the installer.
3440version = [__version__ , 'jupyter' ]
9197 'right' :'q' , 'top' :'r' , 'bottom' :'s' , '_cloneid' :'t' ,
9298 'logx' :'u' , 'logy' :'v' , 'dot' :'w' , 'dot_radius' :'x' ,
9399 'markers' :'y' , 'legend' :'z' , 'label' :'A' , 'delta' :'B' , 'marker_color' :'C' ,
94- 'size_units' :'D' , 'userpan' :'E' , 'scroll' :'F' , 'choices' : 'G' }
100+ 'size_units' :'D' , 'userpan' :'E' , 'scroll' :'F' }
95101
96102# methods are X in {'m': '23X....'}
97103# pos is normally updated as an attribute, but for interval-based trails, it is updated (multiply) as a method
107113 'marker_color' ]
108114
109115__textattrs = ['text' , 'align' , 'caption' , 'title' , 'xtitle' , 'ytitle' , 'selected' , 'label' , 'capture' ,
110- 'append_to_caption' , 'append_to_title' , 'bind' , 'unbind' , 'pause' , 'GSprint' , 'choices' ]
116+ 'append_to_caption' , 'append_to_title' , 'bind' , 'unbind' , 'pause' , 'GSprint' ]
111117
112118def _encode_attr2 (sendval , val , ismethods ):
113119 s = ''
114120 if sendval in __vecattrs : # it would be good to do some kind of compression of doubles
115121 s += "{:.16G},{:.16G},{:.16G}" .format (val [0 ], val [1 ], val [2 ])
116122 elif sendval in __textattrs :
117- if sendval == 'choices' :
118- s2 = ''
119- for v in val :
120- s2 += v + ' '
121- val = s2 [0 :- 1 ]
122- else :
123- # '\n' doesn't survive JSON transmission, so we replace '\n' with '<br>' (and convert back in glowcomm)
124- if not isinstance (val , str ): val = print_to_string (val )
125- val = val .replace ('\n ' , '<br>' )
123+ # '\n' doesn't survive JSON transmission, so we replace '\n' with '<br>' (and convert back in glowcomm)
124+ if not isinstance (val , str ): val = print_to_string (val )
125+ val = val .replace ('\n ' , '<br>' )
126126 s += val
127127 elif sendval == 'rotate' :
128128 for p in val :
@@ -169,6 +169,10 @@ def _encode_attr(D, ismethods): # ismethods is True if a list of method operatio
169169 out .append (s )
170170 return out
171171
172+ if sys .version > '3' :
173+ long = int
174+
175+
172176def list_to_vec (L ):
173177 return vector (L [0 ], L [1 ], L [2 ])
174178
@@ -375,9 +379,14 @@ def handle_msg(self, msg):
375379 obj ._text = evt ['text' ]
376380 obj ._number = evt ['value' ]
377381 # inspect the bound function and see what it's expecting
378- a = signature (obj ._bind )
379- if str (a ) != '()' : obj ._bind ( obj )
380- else : obj ._bind ()
382+ if _ispython3 : # Python 3
383+ a = signature (obj ._bind )
384+ if str (a ) != '()' : obj ._bind ( obj )
385+ else : obj ._bind ()
386+ else : # Python 2
387+ a = getargspec (obj ._bind )
388+ if len (a .args ) > 0 : obj ._bind ( obj )
389+ else : obj ._bind ()
381390 else : ## a canvas event
382391 if 'trigger' not in evt :
383392 cvs = baseObj .object_registry [evt ['canvas' ]]
@@ -392,7 +401,7 @@ def _wait(cvs): # wait for an event
392401 cvs ._waitfor = None
393402 if _isnotebook : baseObj .trigger () # in notebook environment must send methods immediately
394403 while cvs ._waitfor is None :
395- rate (100 )
404+ rate (30 )
396405 return cvs ._waitfor
397406
398407class color (object ):
@@ -547,7 +556,7 @@ class standardAttributes(baseObj):
547556 'extrusion' :[ ['pos' , 'color' , 'start_face_color' , 'end_face_color' ],
548557 [ 'axis' , 'size' , 'up' ],
549558 ['path' , 'shape' , 'visible' , 'opacity' ,'shininess' , 'emissive' ,
550- 'show_start_face' , 'show_end_face' , 'smooth' ,
559+ 'show_start_face' , 'show_end_face' ,
551560 'make_trail' , 'trail_type' , 'interval' , 'show_start_face' , 'show_end_face' ,
552561 'retain' , 'trail_color' , 'trail_radius' , 'texture' , 'pickable' ],
553562 ['red' , 'green' , 'blue' ,'length' , 'width' , 'height' ] ],
@@ -1006,6 +1015,24 @@ def rotate(self, angle=None, axis=None, origin=None):
10061015 self ._pos .value = newpos
10071016 self .addattr ('pos' )
10081017
1018+ def bounding_box (self ):
1019+ centered = ['box' , 'compound' , 'ellipsoid' , 'sphere' , 'simple_sphere' , 'ring' ]
1020+ x = norm (self ._axis )
1021+ y = norm (self ._up )
1022+ z = norm (cross (x ,y ))
1023+ L = self ._size .x
1024+ H = self ._size .y
1025+ W = self ._size .z
1026+ p = vector (self ._pos ) # make a copy of pos, so changes to p won't affect the object
1027+ if self ._objName not in centered :
1028+ p = p + 0.5 * L * x # move to center
1029+ pts = []
1030+ for dx in [- L / 2 , L / 2 ]:
1031+ for dy in [- H / 2 , H / 2 ]:
1032+ for dz in [- W / 2 , W / 2 ]:
1033+ pts .append (p + dx * x + dy * y + dz * z )
1034+ return pts
1035+
10091036 def _on_size_change (self ): # the vector class calls this when there's a change in x, y, or z
10101037 self ._axis .value = self ._axis .norm () * self ._size .x # update axis length when box.size.x is changed
10111038 self .addattr ('size' )
@@ -1431,6 +1458,11 @@ def __init__(self, objList, **args):
14311458 savesize = args ['size' ]
14321459 del args ['size' ]
14331460
1461+ baseObj .sent = False
1462+ while not baseObj .sent : # wait for compounding objects to exist
1463+ if _isnotebook : rate (1000 )
1464+ else : time .sleep (0.001 )
1465+
14341466 self .compound_idx += 1
14351467 args ['_objName' ] = 'compound' + str (self .compound_idx )
14361468 super (compound , self ).setup (args )
@@ -2688,7 +2720,7 @@ def rotate(self, angle=0, axis=None, origin=None):
26882720 c = self ._canvas
26892721 if axis is None : axis = c .up
26902722 if origin is not None and origin != self .pos :
2691- origin = origin + (self .pos - origin ).rotate (angle = angle , axis = axis )
2723+ origin = self . pos + (self .pos - origin ).rotate (angle = angle , axis = axis )
26922724 else :
26932725 origin = self .pos
26942726 if c ._axis .diff_angle (axis ) > 1e-6 :
@@ -3084,6 +3116,7 @@ def handle_event(self, evt): ## events and scene info updates
30843116 # Set attribute_vector.value, which avoids nullifying the
30853117 # on_change functions that detect changes in e.g. obj.pos.y
30863118 obj ._pos .value = list_to_vec (p )
3119+ obj ._origin = obj ._pos
30873120 s = evt ['size' ]
30883121 obj ._size .value = obj ._size0 = list_to_vec (s )
30893122 obj ._axis .value = obj ._size ._x * norm (obj ._axis )
@@ -3097,9 +3130,14 @@ def handle_event(self, evt): ## events and scene info updates
30973130 del evt ['height' ]
30983131 for fct in self ._binds ['resize' ]:
30993132 # inspect the bound function and see what it's expecting
3100- a = signature (fct )
3101- if str (a ) != '()' : fct ( evt )
3102- else : fct ()
3133+ if _ispython3 : # Python 3
3134+ a = signature (fct )
3135+ if str (a ) != '()' : fct ( evt )
3136+ else : fct ()
3137+ else : # Python 2
3138+ a = getargspec (fct )
3139+ if len (a .args ) > 0 : fct ( evt )
3140+ else : fct ()
31033141 else : # pause/waitfor, update_canvas
31043142 if 'pos' in evt :
31053143 pos = evt ['pos' ]
@@ -3119,9 +3157,14 @@ def handle_event(self, evt): ## events and scene info updates
31193157 evt1 = event_return (evt ) ## turn it into an object
31203158 for fct in self ._binds [ev ]:
31213159 # inspect the bound function and see what it's expecting
3122- a = signature (fct )
3123- if str (a ) != '()' : fct ( evt1 )
3124- else : fct ()
3160+ if _ispython3 : # Python 3
3161+ a = signature (fct )
3162+ if str (a ) != '()' : fct ( evt1 )
3163+ else : fct ()
3164+ else : # Python 2
3165+ a = getargspec (fct )
3166+ if len (a .args ) > 0 : fct ( evt1 )
3167+ else : fct ()
31253168 self ._waitfor = evt1 # what pause and waitfor are looking for
31263169 else : ## user can change forward (spin), range/autoscale (zoom), up (touch), center (pan)
31273170 if 'forward' in evt and self .userspin and not self ._set_forward :
@@ -3518,10 +3561,7 @@ def choices(self):
35183561 return self ._choices
35193562 @choices .setter
35203563 def choices (self , value ):
3521- self ._choices = value
3522- if not self ._constructing :
3523- self .addattr ('choices' )
3524- #raise AttributeError('choices cannot be modified after a menu is created')
3564+ raise AttributeError ('choices cannot be modified after a menu is created' )
35253565
35263566 @property
35273567 def index (self ):
@@ -3762,16 +3802,6 @@ def shape(self):
37623802 def shape (self , value ):
37633803 raise AttributeError ('shape cannot be changed after extrusion is created' )
37643804
3765- @property
3766- def smooth (self ):
3767- if self ._constructing :
3768- return self ._smooth
3769- else :
3770- return None
3771- @smooth .setter
3772- def smooth (self , value ):
3773- raise AttributeError ('smooth cannot be changed after extrusion is created' )
3774-
37753805 @property
37763806 def show_start_face (self ):
37773807 if self ._constructing :
@@ -4081,4 +4111,4 @@ def set_browser(type='default'):
40814111 if type == 'pyqt' :
40824112 _browsertype = 'pyqt'
40834113 else :
4084- _browsertype = 'default'
4114+ _browsertype = 'default'
0 commit comments