Search code examples
pythonpython-3.xvpythonglowscript

AttributeError: 'compound' object has no attribute '_origin' in vpython.py


What needs to be done to fix this problem?

At https://www.glowscript.org/#/user/murray.garth/folder/Public/program/Eyeballs I found a GlowScript example that i tried to use as a python3 script.

enter image description here

I modified the header to

#https://www.glowscript.org/#/user/murray.garth/folder/Public/program/Eyeballs
#GlowScript 2.1 VPython
from vpython import *

and changed the true/false references to uppercase.

running

python3 eyeballs.py 

starts a static image enter image description here

and then gives the error message:

compound event return
compound event return
compound event return
Traceback (most recent call last):
  File "eyeballs.py", line 39, in <module>
    world_pos = Head.compound_to_world( vRightEye.pos )
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/vpython/vpython.py", line 1553, in compound_to_world
    v = v-self._origin
AttributeError: 'compound' object has no attribute '_origin'

According to https://www.glowscript.org/docs/VPythonDocs/compound.html the syntax for compound_to_world is:

world_pos = c.compound_to_world(v) 

Which seems to be o.k. to me.

The environment is macports python3

python3 --version
Python 3.7.4

I had installed vpython with

pip install vpython
pip --version
pip 18.1 from /opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip (python 3.7)

Solution

  • This was a tough one. There are some 1.2 million questions on python on stackoverflow. If you search for

    [python]"object has no attribute" 
    

    you get some 12066 results. So that's probably why this question didn'get much attention.

    I tried out the issue with a smaller example according to https://www.glowscript.org/docs/VPythonDocs/compound.html

    from vpython import *
    
    handle = cylinder( size=vec(1,.2,.2),color=vec(0.72,0.42,0) )
    head = box( size=vec(.2,.6,.2), pos=vec(1.1,0,0),color=color.gray(.6) )
    
    hammer = compound([handle, head])
    hammer.axis = vec(1,1,0)
    
    world_pos = hammer.compound_to_world(hammer.axis) 
    

    giving the error mentioned in the question:

    compound event return
    Traceback (most recent call last):
      File "hammer.py", line 10, in <module>
        print (hammer.origin)
      File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/vpython/vpython.py", line 1536, in origin
        return self._origin
    AttributeError: 'compound' object has no attribute '_origin'
    

    The relevant source code lines of vpython.py are:

    @property
    def origin(self):
        return self._origin
    
    @origin.setter
    def origin(self,value): # compound origin cannot be reset
       if not self._constructing:
          raise AttributeError('The compound "origin" attribute is read-only; change "pos" instead.')
       self._origin = value
    
    def world_to_compound(self, v):
            v = v-self._pos
            x_axis = self._axis.hat
            y_axis = self._up.hat
            z_axis = x_axis.cross(y_axis)
            ox = self._size0.x/self._size.x # _size0 is the original size
            oy = self._size0.y/self._size.y
            oz = self._size0.z/self._size.z
            return self._origin + vector(v.dot(x_axis)*ox, v.dot(y_axis)*oy, v.dot(z_axis)*oz)
    
    def compound_to_world(self, v):
            v = v-self._origin
            x_axis = self._axis.hat
            y_axis = self._up.hat
            z_axis = x_axis.cross(y_axis)
            ox = self._size.x/self._size0.x # _size0 is the original size
            oy = self._size.y/self._size0.y
            oz = self._size.z/self._size0.z
            return self._pos + v.x*ox*x_axis + v.y*oy*y_axis + v.z*oz*z_axis
    

    and indeed a few lines further up the constructor does not set any origin. So adding a default origin:

    class compound(standardAttributes):
        compound_idx = 0 # same numbering scheme as in GlowScript
    
        def __init__(self, objList, **args):
            self._origin = vector(0,0,0)
    

    makes the syntax error go away.

    from vpython import *
    
    handle = cylinder( size=vec(1,.2,.2),                   color=vec(0.72,0.42,0) )
    
    head = box( size=vec(.2,.6,.2), pos=vec(1.1,0,0),              color=color.gray(.6) )
    
    hammer = compound([handle, head])
    hammer.axis = vec(1,1,0)
    
    print (hammer.origin)
    
    world_pos = hammer.compound_to_world(hammer.axis)
    print (world_pos)
    

    then gives the result:

    compound event return
    <0, 0, 0>
    <0.6, 1.41421, 0>
    

    and the eyeballs.py code works as expected: enter image description here

    I do not know there to report this bug but I posted a message to the vpython-users group