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

Source Code for Module VisionEgg.SphereMap

   1  # The Vision Egg: SphereMap 
   2  # 
   3  # Copyright (C) 2001-2004 Andrew Straw. 
   4  # Copyright (C) 2005-2008 California Institute of Technology 
   5  # 
   6  # Author: Andrew Straw <astraw@users.sourceforge.net> 
   7  # URL: <http://www.visionegg.org/> 
   8  # 
   9  # Distributed under the terms of the GNU Lesser General Public License 
  10  # (LGPL). See LICENSE.TXT that came with this file. 
  11   
  12  """ 
  13  Stimuli on spheres, including texture maps. 
  14   
  15  """ 
  16   
  17  import math, types 
  18   
  19  import logging 
  20   
  21  import VisionEgg.Core 
  22  import VisionEgg.Textures 
  23  import VisionEgg.Text 
  24  import VisionEgg.Gratings 
  25  import VisionEgg.ThreeDeeMath 
  26  import VisionEgg.ParameterTypes as ve_types 
  27   
  28  import numpy 
  29  import numpy.oldnumeric as Numeric 
  30  import Image 
  31   
  32  import VisionEgg.GL as gl # get all OpenGL stuff in one namespace 
  33   
  34  __version__ = VisionEgg.release_name 
  35   
36 -class AzElGrid(VisionEgg.Core.Stimulus):
37 """Spherical grid of iso-azimuth and iso-elevation lines. 38 39 Parameters 40 ========== 41 anti_aliasing -- (Boolean) 42 Default: True 43 center_azimuth -- (Real) 44 Default: 0.0 45 center_elevation -- (Real) 46 Default: 0.0 47 major_line_color -- (AnyOf(Sequence3 of Real or Sequence4 of Real)) 48 Default: (0.0, 0.0, 0.0) 49 major_line_width -- (Real) 50 Default: 2.0 51 minor_line_color -- (AnyOf(Sequence3 of Real or Sequence4 of Real)) 52 Default: (0.0, 0.0, 1.0) 53 minor_line_width -- (Real) 54 Default: 1.0 55 my_viewport -- (Instance of <class 'VisionEgg.Core.Viewport'>) 56 Default: (determined at runtime) 57 on -- (Boolean) 58 Default: True 59 text_offset -- (Sequence2 of Real) 60 Default: (3, -2) 61 62 Constant Parameters 63 =================== 64 az_major_spacing -- (Real) 65 Default: 30.0 66 az_minor_spacing -- (Real) 67 Default: 10.0 68 el_major_spacing -- (Real) 69 Default: 30.0 70 el_minor_spacing -- (Real) 71 Default: 10.0 72 font_size -- (UnsignedInteger) 73 Default: 24 74 num_samples_per_circle -- (UnsignedInteger) 75 Default: 100 76 radius -- (Real) 77 Default: 1.0 78 text_anchor -- (String) 79 Default: lowerleft 80 text_color -- (AnyOf(Sequence3 of Real or Sequence4 of Real)) 81 Default: (0.0, 0.0, 0.0) 82 use_text -- (Boolean) 83 Default: True 84 """ 85 86 parameters_and_defaults = { 87 'on':(True, 88 ve_types.Boolean), 89 'center_azimuth':(0.0, # 0=right, 90=right 90 ve_types.Real), 91 'center_elevation':(0.0, # 0=right, 90=up 92 ve_types.Real), 93 'minor_line_width':(1.0, 94 ve_types.Real), 95 'major_line_width':(2.0, 96 ve_types.Real), 97 'minor_line_color':((0.0,0.0,1.0), 98 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 99 ve_types.Sequence4(ve_types.Real))), 100 'major_line_color':((0.0,0.0,0.0), 101 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 102 ve_types.Sequence4(ve_types.Real))), 103 'my_viewport':(None, # viewport I'm in 104 ve_types.Instance(VisionEgg.Core.Viewport)), 105 'text_offset':((3,-2), # offset (x,y) to nudge text labels 106 ve_types.Sequence2(ve_types.Real)), 107 'anti_aliasing' : ( True, 108 ve_types.Boolean ), 109 } 110 111 constant_parameters_and_defaults = { 112 'use_text':(True, 113 ve_types.Boolean), 114 'radius':(1.0, 115 ve_types.Real), 116 'az_minor_spacing':(10.0, 117 ve_types.Real), 118 'az_major_spacing':(30.0, 119 ve_types.Real), 120 'el_minor_spacing':(10.0, 121 ve_types.Real), 122 'el_major_spacing':(30.0, 123 ve_types.Real), 124 'num_samples_per_circle':(100, 125 ve_types.UnsignedInteger), 126 'font_size':(24, 127 ve_types.UnsignedInteger), 128 'text_color':((0.0,0.0,0.0), 129 ve_types.AnyOf(ve_types.Sequence3(ve_types.Real), 130 ve_types.Sequence4(ve_types.Real))), 131 'text_anchor':('lowerleft', 132 ve_types.String), 133 } 134 135 __slots__ = ( 136 'cached_minor_lines_display_list', 137 'cached_major_lines_display_list', 138 'text_viewport', 139 'text_viewport_orig', 140 '_gave_alpha_warning', 141 'labels', 142 'labels_xyz', 143 ) 144
145 - def __init__(self,**kw):
146 VisionEgg.Core.Stimulus.__init__(self,**kw) 147 self.cached_minor_lines_display_list = gl.glGenLists(1) # Allocate a new display list 148 self.cached_major_lines_display_list = gl.glGenLists(1) # Allocate a new display list 149 self.__rebuild_display_lists() 150 self.text_viewport = None # not set yet 151 self._gave_alpha_warning = False
152
153 - def __rebuild_display_lists(self):
154 def get_xyz(theta,phi,radius): 155 # theta normally between 0 and pi (north pole to south pole) 156 # phi between -pi and pi 157 y = radius * math.cos( theta ) 158 w = radius * math.sin( theta ) 159 x = w * math.cos( phi ) 160 z = w * math.sin( phi ) 161 return x,y,z
162 def draw_half_great_circle(az): 163 for i in range(cp.num_samples_per_circle/2): 164 # let theta exceed 1 pi to draw 2nd half of circle 165 theta_start = i/float(cp.num_samples_per_circle)*2*math.pi 166 theta_stop = (i+1)/float(cp.num_samples_per_circle)*2*math.pi 167 phi_start = phi_stop = (az-90.0)/180.0*math.pi 168 x_start,y_start,z_start = get_xyz(theta_start,phi_start,cp.radius) 169 x_stop,y_stop,z_stop = get_xyz(theta_stop,phi_stop,cp.radius) 170 gl.glVertex3f(x_start, y_start, z_start) 171 gl.glVertex3f(x_stop, y_stop, z_stop)
172 def draw_iso_elevation_circle(el): 173 # el from -90 = pi to el 90 = 0 174 theta_start = theta_stop = -(el-90) / 180.0 * math.pi 175 for i in range(cp.num_samples_per_circle): 176 phi_start = i/float(cp.num_samples_per_circle)*2*math.pi 177 phi_stop = (i+1)/float(cp.num_samples_per_circle)*2*math.pi 178 x_start,y_start,z_start = get_xyz(theta_start,phi_start,cp.radius) 179 x_stop,y_stop,z_stop = get_xyz(theta_stop,phi_stop,cp.radius) 180 gl.glVertex3f(x_start, y_start, z_start) 181 gl.glVertex3f(x_stop, y_stop, z_stop) 182 183 cp = self.constant_parameters 184 # Weird range construction to be sure to include zero. 185 azs_major = numpy.concatenate(( 186 numpy.arange(0.0,180.0,cp.az_major_spacing), 187 -numpy.arange(0.0,180.0,cp.az_major_spacing)[1:])) 188 azs_minor = numpy.concatenate(( 189 numpy.arange(0.0,180.0,cp.az_minor_spacing), 190 -numpy.arange(0.0,180.0,cp.az_minor_spacing)[1:])) 191 els_major = numpy.concatenate(( 192 numpy.arange(0.0,90.0,cp.el_major_spacing), 193 -numpy.arange(0.0,90.0,cp.el_major_spacing)[1:])) 194 els_minor = numpy.concatenate(( 195 numpy.arange(0.0,90.0,cp.el_minor_spacing), 196 -numpy.arange(0.0,90.0,cp.el_minor_spacing)[1:])) 197 198 gl.glNewList(self.cached_minor_lines_display_list,gl.GL_COMPILE) 199 gl.glBegin(gl.GL_LINES) 200 # az minor 201 for az in azs_minor: 202 if az in azs_major: 203 continue # draw only once as major 204 draw_half_great_circle(az) 205 for el in els_minor: 206 if el in els_major: 207 continue # draw only once as major 208 draw_iso_elevation_circle(el) 209 gl.glEnd() 210 gl.glEndList() 211 212 gl.glNewList(self.cached_major_lines_display_list,gl.GL_COMPILE) 213 gl.glBegin(gl.GL_LINES) 214 for az in azs_major: 215 draw_half_great_circle(az) 216 for el in els_major: 217 draw_iso_elevation_circle(el) 218 gl.glEnd() 219 gl.glEndList() 220 221 if cp.use_text: 222 self.labels = [] 223 self.labels_xyz = [] 224 els_major = list(els_major)+[90.0] # make sure we have north pole 225 for el in els_major: 226 for az in azs_major: 227 theta = -(el-90) / 180.0 * math.pi 228 phi = (az-90.0)/180.0*math.pi 229 x,y,z = get_xyz(theta,phi,cp.radius) 230 self.labels_xyz.append((x,y,z)) 231 self.labels.append( 232 VisionEgg.Text.Text( text = '%.0f, %.0f'%(az,el), 233 font_size = cp.font_size, 234 color = cp.text_color, 235 anchor = cp.text_anchor, 236 ) 237 ) 238 if (el == -90) or (el == 90): 239 self.labels[-1].parameters.text = 'x, %.0f'%(el,) 240 break # only one label at the poles 241 242 self.labels_xyz = Numeric.array(self.labels_xyz) 243
244 - def draw(self):
245 p = self.parameters 246 cp = self.constant_parameters 247 if p.on: 248 # Set OpenGL state variables 249 gl.glDisable( gl.GL_DEPTH_TEST ) 250 gl.glDisable( gl.GL_TEXTURE_2D ) # Make sure textures are not drawn 251 gl.glMatrixMode(gl.GL_MODELVIEW) 252 gl.glPushMatrix() 253 gl.glRotatef(p.center_azimuth,0.0,-1.0,0.0) 254 gl.glRotatef(p.center_elevation,1.0,0.0,0.0) 255 256 if p.anti_aliasing: 257 if len(p.minor_line_color) == 4 and not self._gave_alpha_warning: 258 if p.minor_line_color[3] != 1.0: 259 logger = logging.getLogger('VisionEgg.SphereMap') 260 logger.warning("The parameter anti_aliasing is " 261 "set to true in the AzElGrid " 262 "stimulus class, but the color " 263 "parameter specifies an alpha " 264 "value other than 1.0. To " 265 "acheive the best anti-aliasing, " 266 "ensure that the alpha value for " 267 "the color parameter is 1.0.") 268 self._gave_alpha_warning = 1 269 if len(p.major_line_color) == 4 and not self._gave_alpha_warning: 270 if p.major_line_color[3] != 1.0: 271 logger = logging.getLogger('VisionEgg.SphereMap') 272 logger.warning("The parameter anti_aliasing is " 273 "set to true in the AzElGrid " 274 "stimulus class, but the color " 275 "parameter specifies an alpha " 276 "value other than 1.0. To " 277 "acheive the best anti-aliasing, " 278 "ensure that the alpha value for " 279 "the color parameter is 1.0.") 280 self._gave_alpha_warning = 1 281 gl.glEnable( gl.GL_LINE_SMOOTH ) 282 # allow max_alpha value to control blending 283 gl.glEnable( gl.GL_BLEND ) 284 gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) 285 else: 286 gl.glDisable( gl.GL_BLEND ) 287 288 if len(p.minor_line_color)==3: 289 gl.glColor3f(*p.minor_line_color) 290 elif len(p.minor_line_color)==4: 291 gl.glColor4f(*p.minor_line_color) 292 gl.glLineWidth(p.minor_line_width) 293 gl.glCallList(self.cached_minor_lines_display_list) 294 295 if len(p.major_line_color)==3: 296 gl.glColor3f(*p.major_line_color) 297 elif len(p.major_line_color)==4: 298 gl.glColor4f(*p.major_line_color) 299 gl.glLineWidth(p.major_line_width) 300 gl.glCallList(self.cached_major_lines_display_list) 301 302 if p.anti_aliasing: 303 gl.glDisable( gl.GL_LINE_SMOOTH ) # turn off 304 305 if cp.use_text: 306 my_view = p.my_viewport 307 if (my_view is None) or (not my_view._is_drawing): 308 raise ValueError('use_text is True, but my_viewport not (properly) assigned') 309 310 if self.text_viewport is None or self.text_viewport_orig != my_view: 311 # make viewport for text (uses default orthographic projection) 312 vp = my_view.parameters 313 self.text_viewport = VisionEgg.Core.Viewport(screen=vp.screen, 314 position=vp.position, 315 size=vp.size, 316 anchor=vp.anchor, 317 ) 318 lowerleft = VisionEgg._get_lowerleft(vp.position,vp.anchor,vp.size) 319 self.text_viewport.parameters.projection.stateless_translate(