Clicking on element in ElementArrayStim? "contains" function for elementArrayStim implementation

I think I figured it out! Can anyone think of a faster way to do this? I don’t like having to iterate over the array in the final step…

from psychopy import visual, monitors, core, event, os, data, gui, misc, logging
from random import shuffle
import time, math, random
import numpy as np

try:
	import matplotlib
	if matplotlib.__version__ > '1.2':
		from matplotlib.path import Path as mplPath
	else:
		from matplotlib import nxutils
	haveMatplotlib = True
except Exception:
	haveMatplotlib = False


## Porting psychopy's contains function to elementArrayStim
def contains(thisElementArrayStim, x, y=None, units=None):
	"""Returns True if a point x,y is inside the stimulus' border.

	Can accept variety of input options:
		+ two separate args, x and y
		+ one arg (list, tuple or array) containing two vals (x,y)
		+ an object with a getPos() method that returns x,y, such
			as a :class:`~psychopy.event.Mouse`.

	Returns `True` if the point is within the area defined either by its
	`border` attribute (if one defined), or its `vertices` attribute if
	there is no .border. This method handles
	complex shapes, including concavities and self-crossings.

	Note that, if your stimulus uses a mask (such as a Gaussian) then
	this is not accounted for by the `contains` method; the extent of the
	stimulus is determined purely by the size, position (pos), and
	orientation (ori) settings (and by the vertices for shape stimuli).

	See Coder demos: shapeContains.py
	"""
	# get the object in pixels
	if hasattr(x, 'border'):
		xy = x._borderPix  # access only once - this is a property
		units = 'pix'  # we can forget about the units
	elif hasattr(x, 'verticesPix'):
		# access only once - this is a property (slower to access)
		xy = x.verticesPix
		units = 'pix'  # we can forget about the units
	elif hasattr(x, 'getPos'):
		xy = x.getPos()
		units = x.units
	elif type(x) in [list, tuple, np.ndarray]:
		xy = np.array(x)
	else:
		xy = np.array((x, y))
	# try to work out what units x,y has
	if units is None:
		if hasattr(xy, 'units'):
			units = xy.units
		else:
			units = thisElementArrayStim.units
	if units != 'pix':
		xy = convertToPix(xy, pos=(0, 0), units=units, win=thisElementArrayStim.win)
	# ourself in pixels
	if hasattr(thisElementArrayStim, 'border'):
		poly = thisElementArrayStim._borderPix  # e.g., outline vertices
	else:
		poly = thisElementArrayStim.verticesPix[:, :, 0:2]  # e.g., tesselated vertices

	return any( np.fromiter( ( pointInPolygon(thisPoly, xy[0], xy[1]) for thisPoly in poly[theseTargetIndices] ), np.bool ) )
1 Like