Package VisionEgg :: Module Dots
[frames] | no frames]

Source Code for Module VisionEgg.Dots

  1  # The Vision Egg: Dots 
  2  # 
  3  # Copyright (C) 2001-2003 Andrew Straw. 
  4  # Copyright (C) 2005,2008 California Institute of Technology 
  5  # 
  6  # URL: <http://www.visionegg.org/> 
  7  # 
  8  # Distributed under the terms of the GNU Lesser General Public License 
  9  # (LGPL). See LICENSE.TXT that came with this file. 
 10   
 11  """ 
 12  Random dot stimuli. 
 13   
 14  """ 
 15   
 16  #################################################################### 
 17  # 
 18  #        Import all the necessary packages 
 19  # 
 20  #################################################################### 
 21   
 22  import logging 
 23   
 24  import VisionEgg 
 25  import VisionEgg.Core 
 26  import VisionEgg.ParameterTypes as ve_types 
 27   
 28  import numpy.oldnumeric as Numeric, numpy.oldnumeric.random_array as RandomArray 
 29  import math, types, string 
 30   
 31  import VisionEgg.GL as gl # get all OpenGL stuff in one namespace 
 32   
 33  ### C version of draw_dots() isn't (yet) as fast as Python version: 
 34  ##import VisionEgg._draw_in_c 
 35  ##draw_dots = VisionEgg._draw_in_c.draw_dots # draw in C for speed 
 36   
37 -def draw_dots(xs,ys,zs):
38 """Python method for drawing dots. May be replaced by a faster C version.""" 39 if not (len(xs) == len(ys) == len(zs)): 40 raise ValueError("All input arguments must be same length") 41 gl.glBegin(gl.GL_POINTS) 42 for i in xrange(len(xs)): 43 gl.glVertex3f(xs[i],ys[i],zs[i]) 44 gl.glEnd()
45
46 -class DotArea2D(VisionEgg.Core.Stimulus):
47 """Random dots of constant velocity 48 49 Every dot has the same velocity. Some fraction of the dots all 50 move in the one direction, while the rest move in random 51 directions. Dots wrap around edges. Each dot has a lifespan. 52 53 This is just one example of the endless variations on drawing random dots. 54 55 Parameters 56 ========== 57 anchor -- (String) 58 Default: center 59 anti_aliasing -- (Boolean) 60 Default: True 61 color -- (AnyOf(Sequence3 of Real or Sequence4 of Real)) 62 Default: (1.0, 1.0, 1.0) 63 depth -- (Real) 64 Default: (determined at runtime) 65 dot_lifespan_sec -- (Real) 66 Default: 5.0 67 dot_size -- (Real) 68 Default: 4.0 69 on -- (Boolean) 70 Default: True 71 position -- (Sequence2 of Real) 72 Default: (320.0, 240.0) 73 signal_direction_deg -- (Real) 74 Default: 90.0 75 signal_fraction -- (Real) 76 Default: 0.5 77 size -- (Sequence2 of Real) 78 Default: (300.0, 300.0) 79 velocity_pixels_per_sec -- (Real) 80 Default: 10.0 81 82 Constant Parameters 83 =================== 84 num_dots -- (UnsignedInteger) 85 Default: 100 86 """ 87 88 parameters_and_defaults = { 89 'on' : ( True, 90 ve_types.Boolean ), 91 'position' : ( ( 320.0, 240.0 ), # in eye coordinates 92 ve_types.Sequence2(ve_types.Real) ), 93 'anchor' : ('center', 94 ve_types.String), 95 'size' : ( ( 300.0, 300.0 ), # in eye coordinates 96 ve_types.Sequence2(ve_types.Real) ), 97 'signal_fraction' : ( 0.5, 98 ve_types.Real ), 99 'signal_direction_deg' : ( 90.0, 100 ve_types.Real ), 101 'velocity_pixels_per_sec' : ( 10.0, 102 ve_types.Real ), 103 'dot_lifespan_sec' : ( 5.0, 104 ve_types.Real ), 105 'color' : ((1.0,1.0,1.0), 106 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 107 ve_types.Sequence4(ve_types.Real))), 108 'dot_size' : (4.0, # pixels 109 ve_types.Real), 110 'anti_aliasing' : ( True, 111 ve_types.Boolean ), 112 'depth' : ( None, # set for depth testing 113 ve_types.Real ), 114 'center' : (None, # DEPRECATED -- don't use 115 ve_types.Sequence2(ve_types.Real), 116 "", 117 VisionEgg.ParameterDefinition.DEPRECATED), 118 } 119 120 constant_parameters_and_defaults = { 121 'num_dots' : ( 100, 122 ve_types.UnsignedInteger ), 123 } 124 125 __slots__ = ( 126 'x_positions', 127 'y_positions', 128 'random_directions_radians', 129 'last_time_sec', 130 'start_times_sec', 131 '_gave_alpha_warning', 132 ) 133
134 - def __init__(self, **kw):
135 VisionEgg.Core.Stimulus.__init__(self,**kw) 136 # store positions normalized between 0 and 1 so that re-sizing is ok 137 num_dots = self.constant_parameters.num_dots # shorthand 138 self.x_positions = RandomArray.uniform(0.0,1.0,(num_dots,)) 139 self.y_positions = RandomArray.uniform(0.0,1.0,(num_dots,)) 140 self.random_directions_radians = RandomArray.uniform(0.0,2*math.pi,(num_dots,)) 141 self.last_time_sec = VisionEgg.time_func() 142 self.start_times_sec = None # setup variable, assign later 143 self._gave_alpha_warning = 0
144
145 - def draw(self):
146 # XXX This method is not speed-optimized. I just wrote it to 147 # get the job done. (Nonetheless, it seems faster than the C 148 # version commented out above.) 149 150 p = self.parameters # shorthand 151 if p.center is not None: 152 if not hasattr(VisionEgg.config,"_GAVE_CENTER_DEPRECATION"): 153 logger = logging.getLogger('VisionEgg.Dots') 154 logger.warning("Specifying DotArea2D by deprecated " 155 "'center' parameter deprecated. Use " 156 "'position' parameter instead. (Allows " 157 "use of 'anchor' parameter to set to " 158 "other values.)") 159 VisionEgg.config._GAVE_CENTER_DEPRECATION = 1 160 p.anchor = 'center' 161 p.position = p.center[0], p.center[1] # copy values (don't copy ref to tuple) 162 if p.on: 163 # calculate center 164 center = VisionEgg._get_center(p.position,p.anchor,p.size) 165 166 if p.anti_aliasing: 167 if len(p.color) == 4 and not self._gave_alpha_warning: 168 if p.color[3] != 1.0: 169 logger = logging.getLogger('VisionEgg.Dots') 170 logger.warning("The parameter anti_aliasing is " 171 "set to true in the DotArea2D " 172 "stimulus class, but the color " 173 "parameter specifies an alpha " 174 "value other than 1.0. To " 175 "acheive the best anti-aliasing, " 176 "ensure that the alpha value for " 177 "the color parameter is 1.0.") 178 self._gave_alpha_warning = 1 179 gl.glEnable( gl.GL_POINT_SMOOTH ) 180 # allow max_alpha value to control blending 181 gl.glEnable( gl.GL_BLEND ) 182 gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) 183 else: 184 gl.glDisable( gl.GL_BLEND ) 185 186 now_sec = VisionEgg.time_func() 187 if self.start_times_sec is not None: 188 # compute extinct dots and generate new positions 189 replace_indices = Numeric.nonzero( Numeric.greater( now_sec - self.start_times_sec, p.dot_lifespan_sec) ) 190 Numeric.put( self.start_times_sec, replace_indices, now_sec ) 191 192 new_x_positions = RandomArray.uniform(0.0,1.0, 193 (len(replace_indices),)) 194 Numeric.put( self.x_positions, replace_indices, new_x_positions ) 195 196 new_y_positions = RandomArray.uniform(0.0,1.0, 197 (len(replace_indices),)) 198 Numeric.put( self.y_positions, replace_indices, new_y_positions ) 199 200 new_random_directions_radians = RandomArray.uniform(0.0,2*math.pi, 201 (len(replace_indices),)) 202 Numeric.put( self.random_directions_radians, replace_indices, new_random_directions_radians ) 203 else: 204 # initialize dot extinction values to random (uniform) distribution 205 self.start_times_sec = RandomArray.uniform( now_sec - p.dot_lifespan_sec, now_sec, 206 (self.constant_parameters.num_dots,)) 207 208 signal_num_dots = int(round(p.signal_fraction * self.constant_parameters.num_dots)) 209 time_delta_sec = now_sec - self.last_time_sec 210 self.last_time_sec = now_sec # reset for next loop 211 x_increment_normalized = math.cos(p.signal_direction_deg/180.0*math.pi) * p.velocity_pixels_per_sec / p.size[0] * time_delta_sec 212 y_increment_normalized = -math.sin(p.signal_direction_deg/180.0*math.pi) * p.velocity_pixels_per_sec / p.size[1] * time_delta_sec 213 self.x_positions[:signal_num_dots] += x_increment_normalized 214 self.y_positions[:signal_num_dots] += y_increment_normalized 215 216 num_random_dots = self.constant_parameters.num_dots - signal_num_dots 217 random_x_increment_normalized = Numeric.cos(self.random_directions_radians[signal_num_dots:]) * p.velocity_pixels_per_sec / p.size[0] * time_delta_sec 218 random_y_increment_normalized = -Numeric.sin(self.random_directions_radians[signal_num_dots:]) * p.velocity_pixels_per_sec / p.size[1] * time_delta_sec 219 self.x_positions[signal_num_dots:] += random_x_increment_normalized 220 self.y_positions[signal_num_dots:] += random_y_increment_normalized 221 222 self.x_positions = Numeric.fmod( self.x_positions, 1.0 ) # wrap 223 self.y_positions = Numeric.fmod( self.y_positions, 1.0 ) 224 225 self.x_positions = Numeric.fmod( self.x_positions+1, 1.0 ) # wrap again for values < 1 226 self.y_positions = Numeric.fmod( self.y_positions+1, 1.0 ) 227 228 xs = (self.x_positions - 0.5) * p.size[0] + center[0] 229 ys = (self.y_positions - 0.5) * p.size[1] + center[1] 230 231 if len(p.color)==3: 232 gl.glColor3f(*p.color) 233 elif len(p.color)==4: 234 gl.glColor4f(*p.color) 235 gl.glPointSize(p.dot_size) 236 237 # Clear the modeview matrix 238 gl.glMatrixMode(gl.GL_MODELVIEW) 239 gl.glPushMatrix() 240 241 gl.glDisable(gl.GL_TEXTURE_2D) 242 243 if p.depth is None: 244 depth = 0.0 245 else: 246 gl.glEnable(gl.GL_DEPTH_TEST) 247 depth = p.depth 248 zs = (depth,)*len(xs) # make N tuple with repeat value of depth 249 draw_dots(xs,ys,zs) 250 if p.anti_aliasing: 251 gl.glDisable( gl.GL_POINT_SMOOTH ) # turn off 252 gl.glPopMatrix()
253