Mouse Interactions

Introduction

Mouse interactions involve mouse objects which are not created by the program but are obtained from the mouse attribute of a display object such as scene. For example, to obtain mouse input from the default window created by Visual, refer to scene.mouse.

A mouse object has a group of attributes corresponding to the current state of the mouse. It also has a function getclick(), which returns an object with similar attributes corresponding to the state of the mouse when the user last clicked. If the user has not already clicked the mouse, your program will stop executing until this happens.

Current state of mouse

pos The current 3D position of the mouse cursor; scene.mouse.pos.

Visual always chooses a point in the plane parallel to the screen and passing through display.center.

pick The nearest object in the scene which falls under the cursor, or None. At present only spheres, boxes, cylinders, and convex can be picked. The picked object is scene.mouse.pick.

pickpos The 3D point on the surface of the picked object which falls under the cursor, or None; scene.mouse.pickpos.

camera The current position of the camera, which can be controlled with the mouse by the user; e.g. scene.mouse.camera. For example, mag(scene.mouse.camera-scene.center) is the distance from the center of the scene to the position of the camera

The camera and ray attributes together define all of the 3D points under the mouse cursor.

ray A unit vector pointing from camera in the direction of the mouse cursor. The points under the mouse cursor are exactly { camera + t*ray for t>0}.

project() See Alternative to camera and ray for projecting mouse information onto a given plane.

Getting clicks

clicked The number of clicks which have been queued; e.g. scene.mouse.clicked.

scene.mouse.clicked = 0 may be used to discard input. No value other than zero can be assigned.

getclick() Removes a click from the input queue; scene.mouse.getclick().

If no clicks are waiting in the queue (that is, if scene.mouse.clicked is zero), getclick() waits until the user clicks.

getclick() returns an object with attributes similar to the mouse: pos, pick, pickpos, camera, and ray. These attributes correspond to the state of the mouse when the click took place. For example, scene.mouse.getclick().pos

It is a useful debugging technique to insert scene.mouse.getclick() into your program at a point where you would like to stop temporarily to examine the scene. Then just click to proceed.

 

Alternative to camera and ray

While scene.mouse.camera and scene.mouse.ray are powerful, they can be hard to use. Here is an alternative way to use mouse information:

temp = scene.mouse.project(normal=(0,1,0), d=0)

if temp <> None:

    ball.pos = temp

This projects the mouse cursor onto a plane that is a distance d from the origin of the scene (0,0,0); the plane is perpendicular to the specified normal. If d is not specified, its default value is zero and the plane passes through the origin. It returns a 3D position, or None if the projection of the mouse misses the plane.

For example, if you want the user of your program to be able to use the mouse to place balls in the xy plane, no matter how the user has rotated the point of view, you would use temp= scene.mouse.project(normal=(0,0,1)).

 

Mouse example

This program displays a sphere (which automatically creates a window referred to as scene), then repeatedly waits for a mouse click, prints the mouse position, and displays a small red sphere:

sphere() # display a white sphere for context

while 1:

    if scene.mouse.clicked:

        m = scene.mouse.getclick()

        loc = m.pos

        print loc

        sphere(pos=loc, radius=0.1, color=(1,0,0))

Try running this program. A mouse click is defined as pressing and releasing the mouse button at the same location.

You will find that if you click inside the large white sphere, nothing seems to happen. This is because the mouse click is in the x,y plane, so the little red sphere is buried inside the large white sphere. If you rotate the scene and then click, you'll see that the little red spheres go into the new plane parallel to the screen and passing through display.center. If you want all the red spheres to go into the xy plane, do this:

        loc = m.project(normal=(0,0,1))

        if loc <> None:

            print loc

            sphere(pos=loc, radius=0.1, color=(1,0,0))