1
2
3
4
5
6
7
8
9
10
11 """
12 Random dot stimuli.
13
14 """
15
16
17
18
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
32
33
34
35
36
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
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 ),
92 ve_types.Sequence2(ve_types.Real) ),
93 'anchor' : ('center',
94 ve_types.String),
95 'size' : ( ( 300.0, 300.0 ),
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,
109 ve_types.Real),
110 'anti_aliasing' : ( True,
111 ve_types.Boolean ),
112 'depth' : ( None,
113 ve_types.Real ),
114 'center' : (None,
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
135 VisionEgg.Core.Stimulus.__init__(self,**kw)
136
137 num_dots = self.constant_parameters.num_dots
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
143 self._gave_alpha_warning = 0
144
146
147
148
149
150 p = self.parameters
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]
162 if p.on:
163
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
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
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
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
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 )
223 self.y_positions = Numeric.fmod( self.y_positions, 1.0 )
224
225 self.x_positions = Numeric.fmod( self.x_positions+1, 1.0 )
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
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)
249 draw_dots(xs,ys,zs)
250 if p.anti_aliasing:
251 gl.glDisable( gl.GL_POINT_SMOOTH )
252 gl.glPopMatrix()
253