Example #1
0
class animate_data(object):
    '''
    Creates a object with a widget ready to be inserted in a GTK window, in wich we can 
    draw the current robot pose.
                    
    calling the object will draw the robot pose with the data passed
    calling the method zoom(in,out,reset) will change the zoom of the scene
    calling the method rotate(left,right,reset) will rotate the model along the vertical 
        axe of the scene
    calling the method can_zoom will return the available zoom actions
        -1 zoom out, 0 all, 1 zoom in
    calling the method can_animate return if the animation is available
        bool
    '''
    def __init__(self, user_height = None):
        '''
         Modifiable attributes:
         user_height: as sounds - int default: 180 (centimeters)
        
         Accessible attributes:
         main_widget: widget to be inserted in a GTK window
        '''
        # initialize values
        self.__user_height = 180 if user_height == None else user_height
        self.__upper_arm = self.__user_height * 0.0188
        self.__forearm = self.__user_height * 0.0145
        self.__initial_distance = 20
        self.__initial_angle = 0
        self.__minimum_distance = 10
        self.__maximum_distance = 30
        self.__can_zoom = 0
        self.__can_animate = True
        self.__distance = self.__initial_distance
        self.__angle = self.__initial_angle
        self.__distance_delta = 1.0
        self.__angle_delta = 5.0 * pi /180
        #SHOULDER_X, SHOULDER_Y, SHOULDER_Z, ELBOW_Z
        self.__arm_angles = [0, 0, 0, 0]
        # Try to create a double buffered framebuffer,
        # if not successful then try to create a single
        # buffered one.
        self.__display_mode = MODE_RGB | MODE_DEPTH | MODE_DOUBLE
        try:
            self.__glconfig = Config(mode=self.__display_mode)
        except NoMatches:
            self.__display_mode &= ~MODE_DOUBLE
            self.__glconfig = Config(mode=self.__display_mode)
        # DrawingArea for OpenGL rendering.
        self.__glarea = DrawingArea(self.__glconfig)
        self.__glarea.set_size_request(400, 400)
        self.__label = gtk.Label("Deactivate Animation/Simulation") 
        # The toggle button itself.
        self.main_widget = gtk.ToggleButton()
        # A VBox to pack the glarea and label.
        vbox = gtk.VBox()
        vbox.set_border_width(10)
        vbox.pack_start(self.__glarea)
        vbox.pack_start(self.__label, False, False, 10)
        self.main_widget.add(vbox)
        # connect to the relevant signals.
        self.__glarea.connect_after('realize', self.__update)
        self.__glarea.connect('configure_event', self.__resize)
        self.__glarea.connect('expose_event', self.__draw)
        self.main_widget.connect('toggled', self.__toggle)        
        self.main_widget.show_all()
        return
        
    def __call__(self, values):
        '''
        values: object with the current angles values to draw, in the form of list
        '''
        if not self.__can_animate:
            return
        for index in xrange(4):
            self.__arm_angles[index] = values[index]
        self.__redraw()
        return
    
    def __update(self, widget):
        gldrawable = widget.get_gl_drawable()
        glcontext = widget.get_gl_context()
        # OpenGL begin.
        if not gldrawable.gl_begin(glcontext):
            return
        glClearColor(0.0, 0.0, 0.0, 1.0)
        glClearDepth(1.0)
        glDepthFunc(GL_LESS)    # The type of depth test to do
        glEnable(GL_DEPTH_TEST | GL_LINE_SMOOTH) # Turn on depth testing.
        gldrawable.gl_end()
        # OpenGL end
        return
    
    def __resize(self, widget, event):
        gldrawable = widget.get_gl_drawable()
        glcontext = widget.get_gl_context()
        # OpenGL begin.
        if not gldrawable.gl_begin(glcontext):
            return
        width = widget.allocation.width
        height = widget.allocation.height
        glViewport (0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 300.0)
        glMatrixMode (GL_MODELVIEW)
        gldrawable.gl_end()
        # OpenGL end
        return

    def __draw(self, widget, event):
        x = self.__distance * sin(self.__angle)
        z = self.__distance * cos(self.__angle)
        gldrawable = widget.get_gl_drawable()
        glcontext = widget.get_gl_context()
        # OpenGL begin.
        if not gldrawable.gl_begin(glcontext):
            return
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity ()
        gluLookAt(x, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)  
        #==========================
        glPushMatrix()
        glLineWidth(3)
        glRotatef(self.__arm_angles[0], 1., 0., 0.)
        glRotatef(self.__arm_angles[1], 0., 1., 0.)
        glRotatef(self.__arm_angles[2], 0., 0., 1.)
        glTranslatef(self.__upper_arm, 0., 0.)
        #==========================
        glPushMatrix()
        glColor3f(30./255., 126./255., 30./255.)
        glScalef(self.__upper_arm, 0.4, 1.0)
        self.__draw_cube()       # shoulder
        glPopMatrix()
        #==========================
        glTranslatef(self.__upper_arm, 0., 0.)
        glRotatef(self.__arm_angles[3] , 0., 0., 1.)
        glTranslatef(self.__forearm, 0., 0.)
        glPushMatrix()
        #==========================
        glScalef(self.__forearm, 0.3, 0.75)
        glColor3f(126./255., 30./255., 30./255.)
        self.__draw_cube()      # elbow
        glPopMatrix()
        glPopMatrix()
        #==========================
        if gldrawable.is_double_buffered():
            gldrawable.swap_buffers()
        else:
            glFlush()
        gldrawable.gl_end()
        # OpenGL end
        return

    def __redraw(self):
        self.__glarea.queue_draw()
        return

    def __toggle(self, widget):
        self.__can_animate = not self.main_widget.get_active()
        if self.__can_animate:
            self.__label.set_label("Deactivate Animation/Simulation")
        else:
            self.__label.set_label("Activate Animation/Simulation")
        return

    def __draw_cube(self, size = None):
        size = 1 if size == None else size
        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE)
        glBegin(GL_QUADS)
        #==========================
        glVertex3f(size,size,size)
        glVertex3f(-size,size,size)
        glVertex3f(-size,-size,size)
        glVertex3f(size,-size,size)
        #==========================
        glVertex3f(size,size,-size)
        glVertex3f(-size,size,-size)
        glVertex3f(-size,-size,-size)
        glVertex3f(size,-size,-size)
        #==========================
        glVertex3f(size,size,size)
        glVertex3f(size,-size,size)
        glVertex3f(size,-size,-size)
        glVertex3f(size,size,-size)
        #==========================
        glVertex3f(-size,size,size)
        glVertex3f(-size,-size,size)
        glVertex3f(-size,-size,-size)
        glVertex3f(-size,size,-size)
        #==========================
        glVertex3f(size,size,size)
        glVertex3f(-size,size,size)
        glVertex3f(-size,size,-size)
        glVertex3f(size,size,-size)
        #==========================
        glVertex3f(size,-size,size)
        glVertex3f(-size,-size,size)
        glVertex3f(-size,-size,-size)
        glVertex3f(size,-size,-size)
        #==========================
        glEnd()
        return
    
    def zoom(self, in_out = None):
        # in_out values: -1 zoom out, 0 reset view, 1 zoom in
        if ((in_out == -1) | (in_out == 'out')) & (self.__can_zoom != 1):
            self.__distance += self.__distance_delta
            self.__can_zoom = 1 if self.__distance >= self.__maximum_distance else 0
        elif (in_out == 0) | (in_out == 'reset'):
            self.__distance = self.__initial_distance
            self.__can_zoom = 0
        elif ((in_out == 1) | (in_out == 'in')) & (self.__can_zoom != -1):
            self.__distance -= self.__distance_delta
            self.__can_zoom = -1 if self.__distance <= self.__minimum_distance else 0 
        self.__redraw()
        return
    
    def can_zoom(self):
        return self.__can_zoom
    
    def rotate(self, direction = None):
        # direction values: -1 rotate left, 0 reset view, 1 rotate right
        if (direction == -1) | (direction == 'left'):
            self.__angle -= self.__angle_delta
        elif (direction == 0) | (direction == 'reset'):
            self.__angle = self.__initial_angle
        elif ((direction == 1) | (direction == 'right')):
            self.__angle += self.__angle_delta
        self.__redraw()
        return
    
    def can_animate(self):
        return self.__can_animate