def _get_tobii_pos(self, p): """Convert PsychoPy coordinates to Tobii ADCS coordinates. Args: p: Gaze position (x, y) in PsychoPy coordinate systems. Returns: Gaze position in Tobii ADCS. """ if self.win.units == 'norm': return ((p[0] + 1) / 2, (p[1] - 1) / -2) elif self.win.units == 'height': return (p[0] * (self.win.size[1] / self.win.size[0]) + 0.5, -p[1] + 0.5) elif self.win.units == 'pix': return self._pix2tobii(p) elif self.win.units in ['cm', 'deg', 'degFlat', 'degFlatPos']: if self.win.units == 'cm': p_pix = (cm2pix(p[0], self.win.monitor), cm2pix(p[1], self.win.monitor)) elif self.win.units == 'deg': p_pix = (deg2pix(p[0], self.win.monitor), deg2pix(p[1], self.win.monitor)) elif self.win.units in ['degFlat', 'degFlatPos']: p_pix = (deg2pix( np.array(p), self.win.monitor, correctFlat=True)) return self._pix2tobii(p_pix) else: raise ValueError('unit ({}) is not supported'.format( self.win.units))
def get_tobii_pos(self, p): """ Convert Tobii position to PsychoPy coordinate system. :param p: Position (x, y) """ if self.win.units == 'norm': gp = ((p[0] + 1) / 2, (p[1] + 1) / 2) elif self.win.units == 'height': gp = (p[0] * self.win.size[1] / self.win.size[0] + 0.5, p[1] + 0.5) elif self.win.units == 'pix': gp = (p[0] / self.win.size[0] + 0.5, p[1] / self.win.size[1] + 0.5) elif self.win.units == 'cm': p_pix = (cm2pix(p[0], self.win.monitor), cm2pix(p[1], self.win.monitor)) gp = (p_pix[0] / self.win.size[0] + 0.5, p_pix[1] / self.win.size[1] + 0.5) elif self.win.units == 'deg': p_pix = (deg2pix(p[0], self.win.monitor), deg2pix(p[1], self.win.monitor)) gp = (p_pix[0] / self.win.size[0] + 0.5, p_pix[1] / self.win.size[1] + 0.5) elif self.win.units in ['degFlat', 'degFlatPos']: p_pix = (deg2pix(np.array(p), self.win.monitor, correctFlat=True)) gp = (p_pix[0] / self.win.size[0] + 0.5, p_pix[1] / self.win.size[1] + 0.5) else: raise ValueError('unit ({}) is not supported'.format( self.win.units)) return (gp[0], 1 - gp[1]) # flip vert
def _calcFieldCoordsRendered(self): if self.units in ['norm', 'pix','height']: self._fieldSizeRendered=self.fieldSize self._fieldPosRendered=self.fieldPos elif self.units in ['deg', 'degs']: self._fieldSizeRendered=deg2pix(self.fieldSize, self.win.monitor) self._fieldPosRendered=deg2pix(self.fieldPos, self.win.monitor) elif self.units=='cm': self._fieldSizeRendered=cm2pix(self.fieldSize, self.win.monitor) self._fieldPosRendered=cm2pix(self.fieldPos, self.win.monitor)
def _calcVerticesRendered(self): self.needVertexUpdate=False if self.units in ['norm', 'pix', 'height']: self._verticesRendered=self.vertices self._posRendered=self.pos elif self.units in ['deg', 'degs']: self._verticesRendered=deg2pix(self.vertices, self.win.monitor) self._posRendered=deg2pix(self.pos, self.win.monitor) elif self.units=='cm': self._verticesRendered=cm2pix(self.vertices, self.win.monitor) self._posRendered=cm2pix(self.pos, self.win.monitor) self._verticesRendered = self._verticesRendered * self.size
def _windowUnits2pix(self, win_handle, pos): win = self._iohub_server._psychopy_windows.get(win_handle) win_units = win['units'] monitor = win['monitor'] pos = np.asarray(pos) if win_units == 'pix': return pos elif win_units == 'norm': return pos * win['size'] / 2.0 elif win_units == 'cm': if monitor: return cm2pix(pos, monitor['monitor']) else: # should raise exception? print2err( "iohub Mouse error: Window is using units %s but has no Monitor definition." % win_units) elif win_units == 'deg': if monitor: return deg2pix(pos, monitor['monitor']) else: # should raise exception print2err( "iohub Mouse error: Window is using units %s but has no Monitor definition." % win_units) elif win_units == 'height': return pos * float(win['size'][1])
def setHeight(self,height, log=True): """Set the height of the letters (including the entire box that surrounds the letters in the font). The width of the letters is then defined by the font. """ #height in pix (needs to be done after units) if self.units=='cm': if height==None: self.height = 1.0#default text height else: self.height = height self.heightPix = cm2pix(self.height, self.win.monitor) elif self.units in ['deg', 'degs']: if height==None: self.height = 1.0 else: self.height = height self.heightPix = deg2pix(self.height, self.win.monitor) elif self.units=='norm': if height==None: self.height = 0.1 else: self.height = height self.heightPix = self.height*self.win.size[1]/2 elif self.units=='height': if height==None: self.height = 0.2 else: self.height = height self.heightPix = self.height*self.win.size[1] else: #treat units as pix if height==None: self.height = 20 else: self.height = height self.heightPix = self.height #need to update the font to reflect the change self.setFont(self.fontname, log=False) if log and self.autoLog: self.win.logOnFlip("Set %s height=%.2f" %(self.name, height), level=logging.EXP,obj=self)
def _windowUnitsToPix(self, pos): """Convert user specified window units to 'pix'. This method is the inverse of `_pixToWindowUnits`. Parameters ---------- pos : ArrayLike Position `(x, y)` in 'pix' coordinates to convert. Returns ------- ndarray Position `(x, y)` in window units. """ pos = np.asarray(pos, dtype=np.float32) if self.win is None: return pos if self.win.units == 'pix': return pos elif self.win.units == 'norm': return pos * self.win.size / 2.0 elif self.win.units == 'cm': return cm2pix(pos, self.win.monitor) elif self.win.units == 'deg': return deg2pix(pos, self.win.monitor) elif self.win.units == 'height': return pos * float(self.win.size[1])
def contains(self, x, y=None): """Determines if a point x,y is inside the extent of the stimulus. Can accept: a) two args, x and y; b) one arg, as a point (x,y) that is list-like; or c) an object with a getPos() method that returns x,y, such as a mouse. Returns True if the point is within the area defined by `vertices`. This handles complex shapes, including concavities and self-crossings. Note that, if your stimulus uses a mask (such as a Gaussian blob) then this is not accounted for by the `contains` method; the extent of the stmulus is determined purely by the size, pos and orientation settings (and by the vertices for shape stimuli). See coder demo, shapeContains.py """ if self.needVertexUpdate: self._calcVerticesRendered() if hasattr(x, 'getPos'): x, y = x.getPos() elif type(x) in [list, tuple, numpy.ndarray]: x, y = x[0], x[1] if self.units in ['deg','degs']: x, y = deg2pix(numpy.array((x, y)), self.win.monitor) elif self.units == 'cm': x, y = cm2pix(numpy.array((x, y)), self.win.monitor) if self.ori: oriRadians = numpy.radians(self.ori) sinOri = numpy.sin(oriRadians) cosOri = numpy.cos(oriRadians) x0, y0 = x-self._posRendered[0], y-self._posRendered[1] x = x0 * cosOri - y0 * sinOri + self._posRendered[0] y = x0 * sinOri + y0 * cosOri + self._posRendered[1] return pointInPolygon(x, y, self)
def _calcSizeRendered(self): """Calculate the size of the stimulus in coords of the :class:`~psychopy.visual.Window` (normalised or pixels)""" if self.units in ['norm','pix', 'height']: self._sizeRendered=self.size elif self.units in ['deg', 'degs']: self._sizeRendered=deg2pix(self.size, self.win.monitor) elif self.units=='cm': self._sizeRendered=cm2pix(self.size, self.win.monitor) else: logging.ERROR("Stimulus units should be 'height', 'norm', 'deg', 'cm' or 'pix', not '%s'" %self.units)
def setHeight(self, height, log=True): """Set the height of the letters (including the entire box that surrounds the letters in the font). The width of the letters is then defined by the font. """ #height in pix (needs to be done after units) if self.units == 'cm': if height == None: self.height = 1.0 #default text height else: self.height = height self.heightPix = cm2pix(self.height, self.win.monitor) elif self.units in ['deg', 'degs']: if height == None: self.height = 1.0 else: self.height = height self.heightPix = deg2pix(self.height, self.win.monitor) elif self.units == 'norm': if height == None: self.height = 0.1 else: self.height = height self.heightPix = self.height * self.win.size[1] / 2 elif self.units == 'height': if height == None: self.height = 0.2 else: self.height = height self.heightPix = self.height * self.win.size[1] else: #treat units as pix if height == None: self.height = 20 else: self.height = height self.heightPix = self.height #need to update the font to reflect the change self.setFont(self.fontname, log=False) if log and self.autoLog: self.win.logOnFlip("Set %s height=%.2f" % (self.name, height), level=logging.EXP, obj=self)
def _calcSizeRendered(self): """DEPRECATED in 1.80.00. This funtionality is now handled by _updateVertices() and verticesPix""" #raise DeprecationWarning, "_calcSizeRendered() was deprecated in 1.80.00. This funtionality is nowhanded by _updateVertices() and verticesPix" if self.units in ['norm','pix', 'height']: self._sizeRendered=copy.copy(self.size) elif self.units in ['deg', 'degs']: self._sizeRendered=deg2pix(self.size, self.win.monitor) elif self.units=='cm': self._sizeRendered=cm2pix(self.size, self.win.monitor) else: logging.ERROR("Stimulus units should be 'height', 'norm', 'deg', 'cm' or 'pix', not '%s'" %self.units)
def _calcPosRendered(self): """DEPRECATED in 1.80.00. This funtionality is now handled by _updateVertices() and verticesPix""" #raise DeprecationWarning, "_calcSizeRendered() was deprecated in 1.80.00. This funtionality is now handled by _updateVertices() and verticesPix" if self.units in ['norm', 'pix', 'height']: self._posRendered = copy.copy(self.pos) elif self.units in ['deg', 'degs']: self._posRendered = deg2pix(self.pos, self.win.monitor) elif self.units == 'cm': self._posRendered = cm2pix(self.pos, self.win.monitor)
def _windowUnits2pix(self, pos): if self.win.units == "pix": return pos elif self.win.units == "norm": return pos * self.win.size / 2.0 elif self.win.units == "cm": return cm2pix(pos, self.win.monitor) elif self.win.units == "deg": return deg2pix(pos, self.win.monitor) elif self.win.units == "height": return pos * float(self.win.size[1])
def _windowUnits2pix(self, pos): if self.win.units == 'pix': return pos elif self.win.units == 'norm': return pos * self.win.size / 2.0 elif self.win.units == 'cm': return cm2pix(pos, self.win.monitor) elif self.win.units == 'deg': return deg2pix(pos, self.win.monitor) elif self.win.units == 'height': return pos * float(self.win.size[1])
def _windowUnits2pix(self, pos): if self.win.units == 'pix': return pos elif self.win.units == 'norm': return pos * self.win.size / 2.0 elif self.win.units == 'cm': return cm2pix(pos, self.win.monitor) elif self.win.units == 'deg': return deg2pix(pos, self.win.monitor) elif self.win.units == 'height': return pos * float(self.win.size[1])
def _calcPosRendered(self): """Calculate the pos of the stimulus in pixels""" if self.units == 'pix': self._posRendered = self.pos elif self.units == 'cm': self._posRendered = cm2pix(self.pos, self.win.monitor) elif self.units =='deg': self._posRendered = deg2pix(self.pos, self.win.monitor) elif self.units == 'norm': self._posRendered = self.pos * self.win.size/2.0 elif self.units == 'height': self._posRendered = self.pos * self.win.size[1]
def _calcPosRendered(self): """Calculate the pos of the stimulus in pixels""" if self.units == 'pix': self._posRendered = self.pos elif self.units == 'cm': self._posRendered = cm2pix(self.pos, self.win.monitor) elif self.units == 'deg': self._posRendered = deg2pix(self.pos, self.win.monitor) elif self.units == 'norm': self._posRendered = self.pos * self.win.size / 2.0 elif self.units == 'height': self._posRendered = self.pos * self.win.size[1]
def _calcSizeRendered(self): """DEPRECATED in 1.80.00. This funtionality is now handled by _updateVertices() and verticesPix""" #raise DeprecationWarning, "_calcSizeRendered() was deprecated in 1.80.00. This funtionality is nowhanded by _updateVertices() and verticesPix" if self.units in ['norm', 'pix', 'height']: self._sizeRendered = copy.copy(self.size) elif self.units in ['deg', 'degs']: self._sizeRendered = deg2pix(self.size, self.win.monitor) elif self.units == 'cm': self._sizeRendered = cm2pix(self.size, self.win.monitor) else: logging.ERROR( "Stimulus units should be 'height', 'norm', 'deg', 'cm' or 'pix', not '%s'" % self.units)
def _get_tobii_pos(self, p, units=None): """Convert PsychoPy coordinates to Tobii ADCS coordinates. Args: p: Gaze position (x, y) in PsychoPy coordinate systems. units: The PsychoPy coordinate system of p. Returns: Gaze position in Tobii ADCS. For example: (0,0). """ if units is None: units = self.win.units if units == "norm": return (p[0] / 2 + 0.5, p[1] / -2 + 0.5) elif units == "height": return (p[0] * (self.win.size[1] / self.win.size[0]) + 0.5, -p[1] + 0.5) elif units == "pix": return self._pix2tobii(p) elif units in ["cm", "deg", "degFlat", "degFlatPos"]: if units == "cm": p_pix = (cm2pix(p[0], self.win.monitor), cm2pix(p[1], self.win.monitor)) elif units == "deg": p_pix = ( deg2pix(p[0], self.win.monitor), deg2pix(p[1], self.win.monitor), ) elif units in ["degFlat", "degFlatPos"]: p_pix = deg2pix(np.array(p), self.win.monitor, correctFlat=True) p_pix = tuple(round(pos) for pos in p_pix) return self._pix2tobii(p_pix) else: raise ValueError("unit ({}) is not supported".format(units))
def __init__(self, win, text="Hello World", font="", pos=(0.0,0.0), depth=0, rgb=None, color=(1.0,1.0,1.0), colorSpace='rgb', opacity=1.0, contrast=1.0, units="", ori=0.0, height=None, antialias=True, bold=False, italic=False, alignHoriz='center', alignVert='center', fontFiles=[], wrapWidth=None, flipHoriz=False, flipVert=False, name='', autoLog=True): """ :Parameters: win: A :class:`Window` object. Required - the stimulus must know where to draw itself text: The text to be rendered height: Height of the characters (including the ascent of the letter and the descent) antialias: boolean to allow (or not) antialiasing the text bold: Make the text bold (better to use a bold font name) italic: Make the text italic (better to use an actual italic font) alignHoriz: The horizontal alignment ('left', 'right' or 'center') alignVert: The vertical alignment ('top', 'bottom' or 'center') fontFiles: A list of additional files if the font is not in the standard system location (include the full path) wrapWidth: The width the text should run before wrapping flipHoriz : boolean Mirror-reverse the text in the left-right direction flipVert : boolean Mirror-reverse the text in the up-down direction """ BaseVisualStim.__init__(self, win, units=units, name=name, autoLog=autoLog) self.useShaders = win._haveShaders #use shaders if available by default, this is a good thing self._needUpdate = True self.alignHoriz = alignHoriz self.alignVert = alignVert self.antialias = antialias self.bold=bold self.italic=italic self.text='' #NB just a placeholder - real value set below self.depth=depth self.ori=ori self.wrapWidth=wrapWidth self.flipHoriz = flipHoriz self.flipVert = flipVert self._pygletTextObj=None self.pos= numpy.array(pos, float) #height in pix (needs to be done after units which is done during _Base.__init__) if self.units=='cm': if height==None: self.height = 1.0#default text height else: self.height = height self.heightPix = cm2pix(self.height, win.monitor) elif self.units in ['deg', 'degs']: if height==None: self.height = 1.0 else: self.height = height self.heightPix = deg2pix(self.height, win.monitor) elif self.units=='norm': if height==None: self.height = 0.1 else: self.height = height self.heightPix = self.height*win.size[1]/2 elif self.units=='height': if height==None: self.height = 0.2 else: self.height = height self.heightPix = self.height*win.size[1] else: #treat units as pix if height==None: self.height = 20 else: self.height = height self.heightPix = self.height if self.wrapWidth ==None: if self.units in ['height','norm']: self.wrapWidth=1 elif self.units in ['deg', 'degs']: self.wrapWidth=15 elif self.units=='cm': self.wrapWidth=15 elif self.units in ['pix', 'pixels']: self.wrapWidth=500 if self.units=='norm': self._wrapWidthPix= self.wrapWidth*win.size[0]/2 elif self.units=='height': self._wrapWidthPix= self.wrapWidth*win.size[0] elif self.units in ['deg', 'degs']: self._wrapWidthPix= deg2pix(self.wrapWidth, win.monitor) elif self.units=='cm': self._wrapWidthPix= cm2pix(self.wrapWidth, win.monitor) elif self.units in ['pix', 'pixels']: self._wrapWidthPix=self.wrapWidth #generate the texture and list holders self._listID = GL.glGenLists(1) if not self.win.winType=="pyglet":#pygame text needs a surface to render to self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self.colorSpace=colorSpace if rgb!=None: logging.warning("Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead") self.setColor(rgb, colorSpace='rgb', log=False) else: self.setColor(color, log=False) self._calcPosRendered() for thisFont in fontFiles: pyglet.font.add_file(thisFont) self.setFont(font, log=False) self.opacity = float(opacity) self.contrast = float(contrast) self.setText(text, log=False) #self.width and self.height get set with text and calcSizeRednered is called self._needUpdate = True
def _calcPosRendered(self): """Calculate the pos of the stimulus in coords of the :class:`~psychopy.visual.Window` (normalised or pixels)""" if self.units in ['pix', 'pixels', 'height', 'norm']: self._posRendered=self.pos elif self.units in ['deg', 'degs']: self._posRendered=deg2pix(self.pos, self.win.monitor) elif self.units=='cm': self._posRendered=cm2pix(self.pos, self.win.monitor)
def _calcPosRendered(self): """DEPRECATED in 1.80.00. This funtionality is now handled by _updateVertices() and verticesPix""" #raise DeprecationWarning, "_calcSizeRendered() was deprecated in 1.80.00. This funtionality is now handled by _updateVertices() and verticesPix" if self.units in ['norm','pix', 'height']: self._posRendered= copy.copy(self.pos) elif self.units in ['deg', 'degs']: self._posRendered=deg2pix(self.pos, self.win.monitor) elif self.units=='cm': self._posRendered=cm2pix(self.pos, self.win.monitor)
def __init__(self, win, text="Hello World", font="", pos=(0.0, 0.0), depth=0, rgb=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', opacity=1.0, contrast=1.0, units="", ori=0.0, height=None, antialias=True, bold=False, italic=False, alignHoriz='center', alignVert='center', fontFiles=[], wrapWidth=None, flipHoriz=False, flipVert=False, name='', autoLog=True): """ :Parameters: win: A :class:`Window` object. Required - the stimulus must know where to draw itself text: The text to be rendered height: Height of the characters (including the ascent of the letter and the descent) antialias: boolean to allow (or not) antialiasing the text bold: Make the text bold (better to use a bold font name) italic: Make the text italic (better to use an actual italic font) alignHoriz: The horizontal alignment ('left', 'right' or 'center') alignVert: The vertical alignment ('top', 'bottom' or 'center') fontFiles: A list of additional files if the font is not in the standard system location (include the full path) wrapWidth: The width the text should run before wrapping flipHoriz : boolean Mirror-reverse the text in the left-right direction flipVert : boolean Mirror-reverse the text in the up-down direction """ #what local vars are defined (these are the init params) for use by __repr__ self._initParams = dir() self._initParams.remove('self') BaseVisualStim.__init__(self, win, units=units, name=name, autoLog=False) self.useShaders = win._haveShaders #use shaders if available by default, this is a good thing self._needUpdate = True self.alignHoriz = alignHoriz self.alignVert = alignVert self.antialias = antialias self.bold = bold self.italic = italic self.text = '' #NB just a placeholder - real value set below self.depth = depth self.ori = ori self.wrapWidth = wrapWidth self.flipHoriz = flipHoriz self.flipVert = flipVert self._pygletTextObj = None self.pos = numpy.array(pos, float) #height in pix (needs to be done after units which is done during _Base.__init__) if self.units == 'cm': if height == None: self.height = 1.0 #default text height else: self.height = height self.heightPix = cm2pix(self.height, win.monitor) elif self.units in ['deg', 'degs']: if height == None: self.height = 1.0 else: self.height = height self.heightPix = deg2pix(self.height, win.monitor) elif self.units == 'norm': if height == None: self.height = 0.1 else: self.height = height self.heightPix = self.height * win.size[1] / 2 elif self.units == 'height': if height == None: self.height = 0.2 else: self.height = height self.heightPix = self.height * win.size[1] else: #treat units as pix if height == None: self.height = 20 else: self.height = height self.heightPix = self.height if self.wrapWidth == None: if self.units in ['height', 'norm']: self.wrapWidth = 1 elif self.units in ['deg', 'degs']: self.wrapWidth = 15 elif self.units == 'cm': self.wrapWidth = 15 elif self.units in ['pix', 'pixels']: self.wrapWidth = 500 if self.units == 'norm': self._wrapWidthPix = self.wrapWidth * win.size[0] / 2 elif self.units == 'height': self._wrapWidthPix = self.wrapWidth * win.size[0] elif self.units in ['deg', 'degs']: self._wrapWidthPix = deg2pix(self.wrapWidth, win.monitor) elif self.units == 'cm': self._wrapWidthPix = cm2pix(self.wrapWidth, win.monitor) elif self.units in ['pix', 'pixels']: self._wrapWidthPix = self.wrapWidth #generate the texture and list holders self._listID = GL.glGenLists(1) if not self.win.winType == "pyglet": #pygame text needs a surface to render to self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self.colorSpace = colorSpace if rgb != None: logging.warning( "Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead" ) self.setColor(rgb, colorSpace='rgb', log=False) else: self.setColor(color, log=False) self._calcPosRendered() for thisFont in fontFiles: pyglet.font.add_file(thisFont) self.setFont(font, log=False) self.opacity = float(opacity) self.contrast = float(contrast) self.setText( text, log=False ) #self.width and self.height get set with text and calcSizeRednered is called self._needUpdate = True #set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def degcoord2pix(self, degx, degy, display_index=None): if display_index == self.getIndex(): return psychopy2displayPix( deg2pix(degx, self._psychopy_monitor), cm2pix(degy, self._psychopy_monitor) ) return degx, degy
def _calcXYsRendered(self): if self.units in ['norm','pix','height']: self._XYsRendered=self.xys elif self.units in ['deg', 'degs']: self._XYsRendered=deg2pix(self.xys, self.win.monitor) elif self.units=='cm': self._XYsRendered=cm2pix(self.xys, self.win.monitor)
def _calcDotsXYRendered(self): if self.units in ['norm','pix', 'height']: self._dotsXYRendered=self._dotsXY elif self.units in ['deg','degs']: self._dotsXYRendered=deg2pix(self._dotsXY, self.win.monitor) elif self.units=='cm': self._dotsXYRendered=cm2pix(self._dotsXY, self.win.monitor)
def cmcoord2pix(self, cx, cy, display_index=None): if display_index == self.getIndex(): return psychopy2displayPix(cm2pix(cx, self._psychopy_monitor), cm2pix(cy, self._psychopy_monitor)) return cx, cy