Skip to content

Commit 9a31252

Browse files
Merge pull request #187 from vpython/attach_light
Implement attach_light
2 parents b66d391 + 65aeafc commit 9a31252

File tree

6 files changed

+187
-123
lines changed

6 files changed

+187
-123
lines changed

labextension/vpython/src/glowcommlab.js

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ function control_handler(obj) { // button, menu, slider, radio, checkbox, winpu
444444
}
445445

446446
// attrs are X in {'a': '23X....'} avaiable: none
447-
var attrs = {'a':'pos', 'b':'up', 'c':'color', 'd':'trail_color', // don't use single and double quotes; available: comma, but maybe that would cause trouble
447+
let attrs = {'a':'pos', 'b':'up', 'c':'color', 'd':'trail_color', // don't use single and double quotes; available: comma, but maybe that would cause trouble
448448
'e':'ambient', 'f':'axis', 'g':'size', 'h':'origin', 'i':'textcolor',
449449
'j':'direction', 'k':'linecolor', 'l':'bumpaxis', 'm':'dot_color',
450450
'n':'foreground', 'o':'background', 'p':'ray', 'E':'center', '#':'forward', '+':'resizable',
@@ -471,35 +471,35 @@ var attrs = {'a':'pos', 'b':'up', 'c':'color', 'd':'trail_color', // don't use s
471471
'?':'font', '/':'texture'}
472472

473473
// attrsb are X in {'b': '23X....'}; ran out of easily typable one-character codes
474-
var attrsb = {'a':'userzoom', 'b':'userspin', 'c':'range', 'd':'autoscale', 'e':'fov',
474+
let attrsb = {'a':'userzoom', 'b':'userspin', 'c':'range', 'd':'autoscale', 'e':'fov',
475475
'f':'normal', 'g':'data', 'h':'checked', 'i':'disabled', 'j':'selected',
476476
'k':'vertical', 'l':'min', 'm':'max', 'n':'step', 'o':'value',
477477
'p':'left', 'q':'right', 'r':'top', 's':'bottom', 't':'_cloneid',
478478
'u':'logx', 'v':'logy', 'w':'dot', 'x':'dot_radius',
479479
'y':'markers', 'z':'legend', 'A':'label','B':'delta', 'C':'marker_color',
480480
'D':'size_units', 'E':'userpan', 'F':'scroll', 'G':'choices', 'H':'depth',
481-
'I':'round', 'J':'name'}
481+
'I':'round', 'J':'name', 'K':'offset'}
482482

483483
// methods are X in {'m': '23X....'} available: u
484-
var methods = {'a':'select', 'b':'pos', 'c':'start', 'd':'stop', 'f':'clear', // unused eghijklmnopvxyzCDFAB
484+
let methods = {'a':'select', 'b':'pos', 'c':'start', 'd':'stop', 'f':'clear', // unused eghijklmnopvxyzCDFAB
485485
'q':'plot', 's':'add_to_trail',
486486
't':'follow', 'w':'clear_trail',
487487
'G':'bind', 'H':'unbind', 'I':'waitfor', 'J':'pause', 'K':'pick', 'L':'GSprint',
488488
'M':'delete', 'N':'capture'}
489489

490-
var vecattrs = ['pos', 'up', 'color', 'trail_color', 'axis', 'size', 'origin',
490+
let vecattrs = ['pos', 'up', 'color', 'trail_color', 'axis', 'size', 'origin',
491491
'direction', 'linecolor', 'bumpaxis', 'dot_color', 'ambient', 'add_to_trail', 'textcolor',
492492
'foreground', 'background', 'ray', 'ambient', 'center', 'forward', 'normal',
493-
'marker_color']
493+
'marker_color', 'offset']
494494

495-
var textattrs = ['text', 'align', 'caption', 'title', 'title_align', 'xtitle', 'ytitle', 'selected', 'capture', 'name',
495+
let textattrs = ['text', 'align', 'caption', 'title', 'title_align', 'xtitle', 'ytitle', 'selected', 'capture', 'name',
496496
'label', 'append_to_caption', 'append_to_title', 'bind', 'unbind', 'pause', 'GSprint', 'choices']
497497

498498
// patt gets idx and attr code; vpatt gets x,y,z of a vector
499-
var patt = /(\d+)(.)(.*)/
500-
var vpatt = /([^,]*),([^,]*),(.*)/
501-
var quadpatt = /([^,]*),([^,]*),(.*)/
502-
var plotpatt = /([^,]*),([^,]*)/
499+
const patt = /(\d+)(.)(.*)/
500+
const vpatt = /([^,]*),([^,]*),(.*)/
501+
const quadpatt = /([^,]*),([^,]*),(.*)/
502+
const plotpatt = /([^,]*),([^,]*)/
503503

504504
function decode(data) {
505505
"use strict";
@@ -511,12 +511,12 @@ function decode(data) {
511511
var ms = []
512512

513513
if ('attrs' in data) {
514-
var c = data['attrs']
514+
let c = data['attrs']
515515
for (i=0; i<c.length; i++) { // step through the encoded attributes and methods
516-
var d = c[i]
516+
let d = c[i]
517517
// constructor or appendcmd not currently compressed
518-
var whichlist = d[0] // 'a' or 'b' or 'm'
519-
var datatype = (whichlist == 'm') ? 'method' : 'attr'
518+
let whichlist = d[0] // 'a' or 'b' or 'm'
519+
let datatype = (whichlist == 'm') ? 'method' : 'attr'
520520
s = d.slice(1)
521521
m = s.match(patt)
522522
idx = Number(m[1])
@@ -623,7 +623,8 @@ function handler(data) {
623623
}
624624
*/
625625

626-
626+
627+
627628
if (data.cmds !== undefined && data.cmds.length > 0) handle_cmds(data.cmds)
628629
if (data.methods !== undefined && data.methods.length > 0) handle_methods(data.methods)
629630
if (data.attrs !== undefined && data.attrs.length > 0) handle_attrs(data.attrs)
@@ -650,7 +651,7 @@ function handle_cmds(dcmds) {
650651
var vlst = ['pos', 'color', 'size', 'axis', 'up', 'direction', 'center', 'forward', 'foreground',
651652
'background', 'ambient', 'linecolor', 'dot_color', 'trail_color', 'textcolor', 'attrval',
652653
'origin', 'normal', 'bumpaxis','texpos', 'start_face_color', 'end_face_color', 'marker_color',
653-
'start_normal', 'end_normal']
654+
'start_normal', 'end_normal', 'offset']
654655
if ((obj != 'gcurve') && ( obj != 'gdots' ) ) vlst.push( 'size' )
655656
var cfg = {}
656657
var objects = []
@@ -804,7 +805,15 @@ function handle_cmds(dcmds) {
804805
}
805806
break
806807
}
807-
case 'local_light': {glowObjs[idx] = local_light(cfg); break}
808+
case 'local_light': {
809+
let g = glowObjs[idx] = local_light(cfg)
810+
console.log(g)
811+
if (cfg.offset !== undefined) { // mocking up attach_light
812+
g.__obj = glowObjs[cfg.attach_idx]
813+
g.canvas.attached_lights.push(g)
814+
}
815+
break
816+
}
808817
case 'distant_light': {glowObjs[idx] = distant_light(cfg); break}
809818
case 'canvas': {
810819
if ((typeof isjupyterlab_vpython !== 'undefined') && (isjupyterlab_vpython === true)) {
@@ -904,12 +913,12 @@ function handle_cmds(dcmds) {
904913
async function handle_methods(dmeth) {
905914
"use strict";
906915
//console.log('METHODS')
907-
for (var idmeth=0; idmeth<dmeth.length; idmeth++) { // methods; cmd is ['idx':idx, 'attr':method, 'val':val]
908-
var cmd = dmeth[idmeth]
909-
var idx = cmd.idx
910-
var method = cmd.attr
911-
var val = cmd.val
912-
var obj = glowObjs[idx]
916+
for (let idmeth=0; idmeth<dmeth.length; idmeth++) { // methods; cmd is ['idx':idx, 'attr':method, 'val':val]
917+
let cmd = dmeth[idmeth]
918+
let idx = cmd.idx
919+
let method = cmd.attr
920+
let val = cmd.val
921+
let obj = glowObjs[idx]
913922

914923
if (method == 'GSprint') {
915924
GSprint(val)
@@ -923,17 +932,17 @@ async function handle_methods(dmeth) {
923932
} else if (method === 'add_to_trail') {
924933
obj['_func'] = val
925934
} else if (method === 'bind') {
926-
var evts = val.split(' ')
927-
for (var evt in evts) {
928-
var e = evts[evt]
935+
let evts = val.split(' ')
936+
for (let evt in evts) {
937+
let e = evts[evt]
929938
if (binds.indexOf(e) == -1)
930939
throw new Error('There is no error type "'+e+'"')
931940
}
932941
obj.bind(val, process_binding)
933942
} else if (method === 'unbind') {
934-
var evts = val.split(' ')
935-
for (var evt in evts) {
936-
var e = evts[evt]
943+
let evts = val.split(' ')
944+
for (let evt in evts) {
945+
let e = evts[evt]
937946
if (binds.indexOf(e) == -1)
938947
throw new Error('There is no error type "'+e+'"')
939948
}
@@ -973,17 +982,17 @@ async function handle_methods(dmeth) {
973982
function handle_attrs(dattrs) {
974983
"use strict";
975984
//console.log('ATTRS')
976-
for (var idattrs=0; idattrs<dattrs.length; idattrs++) { // attributes; cmd is {'idx':idx, 'attr':attr, 'val':val}
977-
var cmd = dattrs[idattrs]
978-
var idx = cmd.idx
979-
var obj = glowObjs[idx]
980-
var attr = cmd['attr']
981-
var val = cmd['val']
982-
var triangle_quad = ['v0', 'v1', 'v2', 'v3']
985+
for (let idattrs=0; idattrs<dattrs.length; idattrs++) { // attributes; cmd is {'idx':idx, 'attr':attr, 'val':val}
986+
let cmd = dattrs[idattrs]
987+
let idx = cmd.idx
988+
let obj = glowObjs[idx]
989+
let attr = cmd['attr']
990+
let val = cmd['val']
991+
let triangle_quad = ['v0', 'v1', 'v2', 'v3']
983992
if (val instanceof vec) {
984993
if (attr === 'pos' && (obj instanceof points || obj instanceof curve)) {
985-
var ptlist = []
986-
for (var kk = 0; kk < val.length; kk++) {
994+
let ptlist = []
995+
for (let kk = 0; kk < val.length; kk++) {
987996
ptlist.push( val[kk] )
988997
}
989998
obj[attr] = ptlist

vpython/test/test_namespace.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
'atan2',
2323
'atanh',
2424
'attach_arrow',
25+
'attach_light',
2526
'attach_trail',
2627
'baseObj',
2728
'box',

vpython/vpython.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
# List of names that will be imported from this file with import *
2020
__all__ = ['Camera', 'GlowWidget', 'version', 'GSversion', 'Mouse', 'arrow', 'attach_arrow',
21-
'attach_trail', 'baseObj', 'box', 'bumpmaps', 'button',
21+
'attach_light', 'attach_trail', 'baseObj', 'box', 'bumpmaps', 'button',
2222
'canvas', 'checkbox', 'clock', 'color', 'combin', 'compound', 'cone', 'controls',
2323
'curve', 'curveMethods', 'cylinder', 'distant_light', 'ellipsoid',
2424
'event_return', 'extrusion', 'faces', 'frame', 'gcurve', 'gdots',
@@ -98,7 +98,7 @@
9898
'logx':'u', 'logy':'v', 'dot':'w', 'dot_radius':'x',
9999
'markers':'y', 'legend':'z', 'label':'A', 'delta':'B', 'marker_color':'C',
100100
'size_units':'D', 'userpan':'E', 'scroll':'F', 'choices':'G', 'depth':'H',
101-
'round':'I', 'name':'J'}
101+
'round':'I', 'name':'J', 'offset':'K', 'L':'attach_idx'}
102102

103103
# methods are X in {'m': '23X....'}
104104
# pos is normally updated as an attribute, but for interval-based trails, it is updated (multiply) as a method
@@ -111,7 +111,7 @@
111111
__vecattrs = ['pos', 'up', 'color', 'trail_color', 'axis', 'size', 'origin',
112112
'direction', 'linecolor', 'bumpaxis', 'dot_color', 'ambient', 'add_to_trail',
113113
'foreground', 'background', 'ray', 'ambient', 'center', 'forward', 'normal',
114-
'marker_color']
114+
'marker_color', 'offset']
115115

116116
__textattrs = ['text', 'align', 'caption', 'title', 'xtitle', 'ytitle', 'selected', 'label', 'capture', 'name',
117117
'append_to_caption', 'append_to_title', 'bind', 'unbind', 'pause', 'GSprint', 'choices']
@@ -208,6 +208,7 @@ def empty(cls):
208208

209209
@classmethod
210210
def handle_attach(cls): # called when about to send data to the browser
211+
211212
## update every attach_arrow if relevant vector has changed
212213
for aa in cls.attach_arrows:
213214
if not aa._run: continue
@@ -524,9 +525,9 @@ class standardAttributes(baseObj):
524525
['visible', 'xoffset', 'yoffset', 'font', 'height', 'opacity',
525526
'border', 'line', 'box', 'space', 'align', 'linewidth', 'pixel_pos'],
526527
['text']],
527-
'local_light':[['pos', 'color'],
528+
'local_light':[['pos', 'color', 'offset'],
528529
[],
529-
['visible'],
530+
['visible', 'attach_idx'],
530531
[]],
531532
'distant_light':[['direction', 'color'],
532533
[],
@@ -617,6 +618,8 @@ def setup(self, args):
617618
self._size_units = 'pixels'
618619
self._texture = None
619620
self._pickable = True
621+
self._offset = vector(0,0,0)
622+
self._attach_idx = None
620623
self._save_oldaxis = None # used in linking axis and up
621624
self._save_oldup = None # used in linking axis and up
622625
_special_clone = None
@@ -1390,6 +1393,23 @@ def attach_arrow(o, attr, **args): # factory function returns arrow with special
13901393
_last_val=vector(134.472, 789.472, 465.472), _last_pos=vector(134.472, 789.472, 465.472))
13911394
baseObj.attach_arrows.append(a)
13921395
return a
1396+
1397+
def attach_light(o, **args): # factory function returns local_light with special attributes
1398+
'''
1399+
The object "o" will have a local_light attached with options "offset" and "color".
1400+
The local_light will constantly be positioned at o.pos plus the offset.
1401+
'''
1402+
if not isinstance(o.pos, vector): raise AttributeError("Cannot attach a light to an object that has no pos attribute.")
1403+
if 'color' in args:
1404+
if not isinstance(args['color'], vector): raise AttributeError("The color attribute must be a vector.")
1405+
else:
1406+
args['color'] = o.color # default color
1407+
if 'offset' in args:
1408+
if not isinstance(args['offset'], vector): raise AttributeError('The attach_light attribute "offset" must be a vector.')
1409+
else:
1410+
args['offset'] = vector(0,0,0) # default offset
1411+
a = local_light(pos=o.pos+args['offset'], attach_idx=o.idx, color=args['color'], offset=args['offset'])
1412+
return a
13931413

13941414
class attach_trail(standardAttributes):
13951415
def __init__(self, obj, **args):
@@ -3350,6 +3370,24 @@ def __init__(self, **args):
33503370
if (canvas.get_selected() is not None):
33513371
canvas.get_selected()._lights.append(self)
33523372

3373+
@property
3374+
def offset(self):
3375+
return self._offset
3376+
@offset.setter
3377+
def offset(self, value):
3378+
self._offset = vector(value)
3379+
if not self._constructing:
3380+
self.addattr('offset')
3381+
3382+
@property
3383+
def attach_idx(self):
3384+
return self._attach_idx
3385+
@attach_idx.setter
3386+
def attach_idx(self, value):
3387+
self._attach_idx = vector(value)
3388+
if not self._constructing:
3389+
self.addattr('attach_idx')
3390+
33533391
class distant_light(standardAttributes):
33543392
def __init__(self, **args):
33553393
args['_default_size'] = vector(1,1,1)

vpython/vpython_libraries/glow.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)