.overlaps() method fails with rectangles

Usually, the overlaps method for visual objects works fine for me, but I’ve just run into a problem with it that has completely baffled me. When I try to check whether two rectangles overlap, it gives me False, even when they obviously do overlap. I made a variation on the shapeContains demo code to check what happened, and it appears that the overlap is only detected when the end point of one rectangle is inside the other rectangle. This is the code I used:

from __future__ import division
from psychopy import visual, event, core

win = visual.Window(size=(10, 10), fullScreen=False, monitor='testMonitor', units='deg')
mouse = event.Mouse()
txt = 'click the shape to quit\nscroll to adjust circle'
instr = visual.TextStim(win, text=txt, pos=(0, -.7), opacity=0.5)
msg = visual.TextStim(win, text=' ', pos=(0, -.4))

# a target rectangle (horizontal bar):
shape = visual.Rect(win, width=5, height=0.2, lineWidth=1, lineColor=(-1,1,-1), fillColor=(-1,1,-1), pos=[0,0], autoLog=False, name='green_goal_hr')

# another rectangle (diagonal bar):
bufzone = visual.ShapeStim(win, lineWidth=0, fillColor='green', opacity=0.2, vertices=((-3.0,-3.0),(-2.8,-3.2),(0.5,0.5),(0.3,0.7)), autoLog=False)

# loop until detect a click inside the shape:
while not mouse.isPressedIn(shape):
    instr.draw()
    # diagonal bar follows mouse pointer:
    bufzone.pos = mouse.getPos()  # follow the mouse
    # is the mouse inside the shape (hovering over it)?
    if shape.contains(mouse):
        msg.text = 'inside'
        shape.opacity = bufzone.opacity = 1
    elif shape.overlaps(bufzone):
        msg.text = 'near'
        shape.opacity = bufzone.opacity = 0.6
    else:
        msg.text = 'far away'
        shape.opacity = bufzone.opacity = 0.2
    bufzone.draw()  # drawing helps visualize the mechanics
    msg.draw()
    shape.draw()
    win.flip()

win.close()
core.quit()

What I was actually trying to do was the following: in my experiment, circles move around in a box with a wall in the middle, through which they can sometimes pass (see picture below). In two of the corners of the box, there are ‘goals’, one green and one red. Each time a circle reaches the wall in the middle, a probe (small dot) might appear, and I want to capture some information about the scene at that moment, including whether the circle was moving towards one of the goals. The easiest way, I figured, was to make a line that runs from the circle towards the edge of the box, extrapolating its velocity such that it definitely reaches the edge of the box, so that I can check whether this ‘future path’ overlaps with one of the goals. Since .overlap() does not work with lines, I used rectangular shapestims, but that appeared not to work.

It would really help me if someone knows a better solution to checking where my circles are going (a fast method, because the circles need to keep moving), but I’m already happy if my post helps to improve .overlaps().

Hi @Andrea, I believe you can do this in Builder. See the attached example - note I created this example in the most recent version of Psychopy found here.

In this example, there are lateral lines of red and green, and a center line. A circle moves with the mouse pointer. A code component is used for dynamic changes to the stim. If the circle crosses the centre line, a function is called in the code component that checks whether the x position of the mouse is increasing or decreasing. The circle changes color depending on the direction the circle is travelling. This should give you some idea of the flexibility of Builder to help you create your experiment.

collision.psyexp (11.7 KB)

Hi @dvbridges, thanks for the quick reply!

Your solution is not exactly what I’m looking for. I have velocity vectors for all four circles, so knowing whether they’re moving up, down, left or right is not a problem. What I’m trying to find out is whether a circle, if it keeps going in the direction it was heading, will eventually end up hitting one of the ‘goal’ areas (and the same for if it would bounce off the wall in the center of the screen).

I’ve also tried looping through its future positions until it either hits a goal or falls outside the screen (see below), but that takes so much time that the frame actually freezes for a bit.

while field.contains(pos):
    pos += vel
    if greengoal_horiz.contains(pos) or greengoal_verti.contains(pos):
        return 'green'
    elif redgoal_horiz.contains(pos) or redgoal_verti.contains(pos):
        return 'red'
return 'none'

If you are predicting the trajectory, I think you would be better off calculating the slope and trajectory and checking whether or not the predicted trajectory overlaps the position of your goals. This is example works for 1 circle and for one border. You just need to complete the code to get all borders working.

This example takes the mouse positions from the last 10 frames, calculates the slope, creates a line showing the trajectory and determines whether the end point of the trajectory overlaps with the position of the border (for right side only). Border changes color if overlap occurs.

collision.psyexp (15.2 KB)