rss_feed

Python CAD Tutorial 04 - Mouse coordinates in 3D space

homeHome
pagesGTK-3
pagespython
pagescad
pagesopengl

View/Download Code

Mouse coordinates

We have a camera and something displayed on the screen, now let's start taking input from the mouse. We will create a new mouse handling class which will allow us to store a series of clicks. We can also use the stored positions for previews at a later date.The new class contains a few simple methods:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class mouse_state:
    """ store mouse clicks so we know where to draw and what to create """
    button1 = 0
    button2 = 0
    button3 = 0
    cordinates = []
    x = y = 0

    def append(self, x, y, button=1):
        """ store a new mouse click """
        self.x = x
        self.y = y
        self.cordinates.append((x, y,))

    def get_click_position(self):
        """ return the position of the last click """
        return self.x, self.y

    def get_points(self):
        """ return all stored points we may want to store lots of points when drawing a line for example"""
        if len(self.cordinates) != 2:
            return None
        result = self.cordinates
        self.cordinates = []
        return result

    def count(self):
        """return number of stored points """
        return len(self.cordinates)

    def clear(self):
        self.x = self.y = 0
        self.cordinates = []

Let's add a new method to our camera class, which will convert mouse clicks in 2 dimensional space into 3 dimensional coordinates so we can position something on the screen.The 'getclick point' method below takes a tuple containing the x and y coordinates from the mouse. It then converts the y position because in opengl '0' is at the bottom, but drawing area widget has '0' at the top. Finally it uses gluUnProject to convert from 2d space to 3d space.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    def get_click_point(self, pos):
        """ convert 2d click in the viewport to 3d point in space"""
        viewport = glGetIntegerv(GL_VIEWPORT)
        modelview = glGetDoublev(GL_MODELVIEW_MATRIX)
        projection = glGetDoublev(GL_PROJECTION_MATRIX)

        #convert screen ccordinate to opengl cordinates, this means modifying the y axes only
        x, y = pos[0], self.viewport[1] - pos[1]

        #use unproject to calculate the point and store the resutl in a point object
        return createpoint(gluUnProject(x, y, 0.20, modelview, projection, viewport), (250, 0, 0))

Let's handle the mouse click events in the drawing area; we will store the 2d x and y coordinates of a mouse click in our new mousestate class. Now we adjust the ondraw method to draw a point at the location we clicked on the page, which gives us visual feedback that everything is working correctly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    def mouse_click(self, widget, event):
        self.mouse.append(event.x, event.y, event.button)
        self.test_point = self.camera.get_click_point(self.mouse.get_click_position())
        self.on_draw()

    def on_draw(self, *args):
        """ Test code to make sure we can draw a pixel successfully,
        also test we can position our new camera class to lookat the pixel"""
        #lets not look directly at the point we are drawing, demonstrating we can lookat points in space
        self.camera.lookat.x = 20
        self.camera.lookat.y = 20
        self.camera.lookat.z = -20

        #recalculate our camera based on the new settings
        self.camera.update()

        glClearColor(0.0, 0.0, 0.0, 0.0)
        glClear(GL_COLOR_BUFFER_BIT)
        self.glwrap.draw_start()

        #place a point we can lookat that will be positioned in our field of view.
        self.test_point.draw()

        self.glwrap.draw_finish()