Python CAD Tutorial 04 - Mouse coordinates in 3D space

View/Download Code


Figure 1: 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:

  • append() to add a new click
  • count() to return the number of stored clicks
  • getclickposition() returns the last clicked position
  • getpoints() returns a list of the stored locations, and resets the list
  • clear() resets the stored coordinates.
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 'getclickpoint' 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.

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 mousestateclass. 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.

def mouse_click(self, widget, event):
    self.mouse.append(event.x, event.y, event.button)
    self.test_point =

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 = 20 = 20 = -20

    #recalculate our camera based on the new settings

    glClearColor(0.0, 0.0, 0.0, 0.0)

    #place a point we can lookat that will be positioned in our field of view.