def init_motors(): ###data structure to construct the rotation sign for rotary motor numSeg = 20 rotS = map((lambda n: pi/2+n*2.0*pi/numSeg), range(numSeg*3/4 + 1)) zOffset = 0.005 scaleS = 0.4 drawing_globals.rotS0n = rotS0n = map( (lambda a: (scaleS*cos(a), scaleS*sin(a), 0.0 - zOffset)), rotS) drawing_globals.rotS1n = rotS1n = map( (lambda a: (scaleS*cos(a), scaleS*sin(a), 1.0 + zOffset)), rotS) ###Linear motor arrow sign data structure drawing_globals.halfHeight = 0.45 drawing_globals.halfEdge = halfEdge = 3.0 * scaleS * sin(pi/numSeg) arrow0Vertices = [ (rotS0n[-1][0]-halfEdge, rotS0n[-1][1], rotS0n[-1][2]), (rotS0n[-1][0]+halfEdge, rotS0n[-1][1], rotS0n[-1][2]), (rotS0n[-1][0], rotS0n[-1][1] + 2.0*halfEdge, rotS0n[-1][2])] arrow0Vertices.reverse() drawing_globals.arrow0Vertices = arrow0Vertices drawing_globals.arrow1Vertices = [ (rotS1n[-1][0]-halfEdge, rotS1n[-1][1], rotS1n[-1][2]), (rotS1n[-1][0]+halfEdge, rotS1n[-1][1], rotS1n[-1][2]), (rotS1n[-1][0], rotS1n[-1][1] + 2.0*halfEdge, rotS1n[-1][2])] drawing_globals.halfEdge = halfEdge = 1.0/3.0 ##1.0/8.0 drawing_globals.linearArrowVertices = [ (0.0, -halfEdge, 0.0), (0.0, halfEdge, 0.0), (0.0, 0.0,2*halfEdge)] return
def wpdg(series,detrend=0,win='triangle'): samples = Numeric.shape(series)[0] wrange = Numeric.arange(0,samples,dtype='d') / (samples - 1.0); if win == 'blackman': window = 0.42 - 0.5 * Numeric.cos(2*math.pi*wrange) + 0.08 * Numeric.cos(4*math.pi*wrange) elif win == 'sin4': window = Numeric.sin(math.pi*wrange)**4.0 else: # if we don't recognize a window, default to triangle pdlen = (samples - 1) / 2.0 window = 1.0 - abs(Numeric.arange(0,samples,dtype='d') - pdlen) / (pdlen) wseries = series.copy() if detrend == 1: leastsquares(wseries,detrend=1) wseries *= window weight = samples * Numeric.sum(window ** 2) wpdgram = pdg(wseries) * (1.0 * samples**2 / weight) return wpdgram
def CalculateTorus(self, a, b, u, v): """calculate point on torus""" pi2 = 2 * pi #transformation function - torus cf = cos(pi2*u) sf = sin(pi2*u) ct = cos(pi2*v) st = sin(pi2*v) #point on torus return Triple((a+b*ct)*cf, (a+b*ct)*sf, b*st)
def CalculateTorus(self, a, b, u, v): """calculate point on torus""" pi2 = 2 * pi #transformation function - torus cf = cos(pi2 * u) sf = sin(pi2 * u) ct = cos(pi2 * v) st = sin(pi2 * v) #point on torus return Triple((a + b * ct) * cf, (a + b * ct) * sf, b * st)
def rotz(angle): ret = numerix.identity(4).astype(numerix.Float) ret[0, 0] = ret[1, 1] = numerix.cos(angle) sn = numerix.sin(angle) ret[0, 1] = -sn ret[1, 0] = sn return ret
def _compute_ribbon_point(origin, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn , theta_offset ): """ """ ##handedness = -1 ##theta_offset = 0.0 #turn_angle = twistPerBase ##turn_angle = (handedness * 2 * pi) / basesPerTurn turn_angle = (2 * pi) / basesPerTurn ## axial_offset = unitVectorAlongLength * duplexRise cY = unitVectorAlongLadderStep cZ = unitDepthVector theta = turn_angle * numberOfBasesDrawn + theta_offset # in radians y = cos(theta) * peakDeviationFromCenter z = sin(theta) * peakDeviationFromCenter ## vx = axial_offset # a Vector p = origin + y * cY + z * cZ return p
def polarToCartesian(rtp): """ Convert polar coordinate array to cartesian coordinate array: C{ r, S{theta}, S{phi} -> x,y,z } @param rtp: array of cartesian coordinates (r, theta, phi) @type rtp: array @return: array of cartesian coordinates (x, y, z) @rtype: array """ x = rtp[:, 0] * N.cos(rtp[:, 1]) * N.sin(rtp[:, 2]) y = rtp[:, 0] * N.sin(rtp[:, 1]) * N.sin(rtp[:, 2]) z = rtp[:, 0] * N.cos(rtp[:, 2]) return N.transpose(N.concatenate(([x], [y], [z])))
def rotz(angle): ret = numerix.identity(4).astype(numerix.Float) ret[0,0] = ret[1,1] = numerix.cos(angle) sn = numerix.sin(angle) ret[0,1] = -sn ret[1,0] = sn return ret
def polarToCartesian( rtp ): """ Convert polar coordinate array to cartesian coordinate array: C{ r, S{theta}, S{phi} -> x,y,z } @param rtp: array of cartesian coordinates (r, theta, phi) @type rtp: array @return: array of cartesian coordinates (x, y, z) @rtype: array """ x = rtp[:,0] * N.cos( rtp[:,1] ) * N.sin( rtp[:,2] ) y = rtp[:,0] * N.sin( rtp[:,1] ) * N.sin( rtp[:,2] ) z = rtp[:,0] * N.cos( rtp[:,2] ) return N.transpose( N.concatenate( ([x],[y],[z]) ) )
def setangle(self, theta): """ Set the quaternion's rotation to theta (destructive modification). (In the same direction as before.) """ theta = Numeric.remainder(theta / 2.0, math.pi) self.vec[1:] = norm(self.vec[1:]) * Numeric.sin(theta) self.vec[0] = Numeric.cos(theta) self.__reset() return self
def proj2sphere(x, y): """ project a point from a tangent plane onto a unit sphere """ d = (x*x + y*y) ** .5 theta = math.pi * 0.5 * d s = Numeric.sin(theta) if d > 0.0001: return V(s*x/d, s*y/d, Numeric.cos(theta)) else: return V(0.0, 0.0, 1.0)
def eulerRotation(alpha, beta, gamma): """ Builds a rotation matrix from successive rotations: 1. rotation about y-axis by angle alpha 2. rotation about x-axis by angle beta 3. rotation about z-axis by angle gamma @author: Michael Habeck @param alpha: euler angle S{alpha} @type alpha: float @param beta: euler angle S{beta} @type beta: float @param gamma: euler angle S{gamma} @type gamma: float @return: 3 x 3 array of float @rtype: array """ cos_alpha = N.cos(alpha) sin_alpha = N.sin(alpha) cos_beta = N.cos(beta) sin_beta = N.sin(beta) cos_gamma = N.cos(gamma) sin_gamma = N.sin(gamma) R = N.zeros((3, 3), N.Float32) R[0][0] = cos_gamma * cos_alpha - sin_gamma * cos_beta * sin_alpha R[0][1] = cos_gamma * sin_alpha + sin_gamma * cos_beta * cos_alpha R[0][2] = sin_gamma * sin_beta R[1][0] = -sin_gamma * cos_alpha - cos_gamma * cos_beta * sin_alpha R[1][1] = -sin_gamma * sin_alpha + cos_gamma * cos_beta * cos_alpha R[1][2] = cos_gamma * sin_beta R[2][0] = sin_beta * sin_alpha R[2][1] = -sin_beta * cos_alpha R[2][2] = cos_beta return R
def gabor(x, y, xsigma, ysigma, frequency, phase): """ Gabor pattern (sine grating multiplied by a circular Gaussian). """ if xsigma == 0.0 or ysigma == 0.0: return x * 0.0 with float_error_ignore(): x_w = divide(x, xsigma) y_h = divide(y, ysigma) p = exp(-0.5 * x_w * x_w + -0.5 * y_h * y_h) return p * 0.5 * cos(2 * pi * frequency * y + phase)
def gabor(x, y, xsigma, ysigma, frequency, phase): """ Gabor pattern (sine grating multiplied by a circular Gaussian). """ if xsigma==0.0 or ysigma==0.0: return x*0.0 with float_error_ignore(): x_w = divide(x,xsigma) y_h = divide(y,ysigma) p = exp(-0.5*x_w*x_w + -0.5*y_h*y_h) return p * 0.5*cos(2*pi*frequency*y + phase)
def rotxyz(angles): ret = numerix.identity(4).astype(numerix.Float) ret[1,1] = ret[2,2] = numerix.cos(angles[0]) sn = numerix.sin(angles[0]) ret[1,2] = -sn ret[2,1] = sn cs = numerix.cos(angles[1]) ret[0,0] = cs ret[2,2] += cs sn = numerix.sin(angles[1]) ret[0,2] = sn ret[2,0] = -sn cs = numerix.cos(angles[2]) ret[0,0] += cs ret[1,1] += cs sn = numerix.sin(angles[2]) ret[0,1] = -sn ret[1,0] = sn return ret
def rotxyz(angles): ret = numerix.identity(4).astype(numerix.Float) ret[1, 1] = ret[2, 2] = numerix.cos(angles[0]) sn = numerix.sin(angles[0]) ret[1, 2] = -sn ret[2, 1] = sn cs = numerix.cos(angles[1]) ret[0, 0] = cs ret[2, 2] += cs sn = numerix.sin(angles[1]) ret[0, 2] = sn ret[2, 0] = -sn cs = numerix.cos(angles[2]) ret[0, 0] += cs ret[1, 1] += cs sn = numerix.sin(angles[2]) ret[0, 1] = -sn ret[1, 0] = sn return ret
def eulerRotation(alpha, beta, gamma): """ Builds a rotation matrix from successive rotations: 1. rotation about y-axis by angle alpha 2. rotation about x-axis by angle beta 3. rotation about z-axis by angle gamma @author: Michael Habeck @param alpha: euler angle S{alpha} @type alpha: float @param beta: euler angle S{beta} @type beta: float @param gamma: euler angle S{gamma} @type gamma: float @return: 3 x 3 array of float @rtype: array """ cos_alpha = N.cos(alpha); sin_alpha = N.sin(alpha) cos_beta = N.cos(beta); sin_beta = N.sin(beta) cos_gamma = N.cos(gamma); sin_gamma = N.sin(gamma) R = N.zeros((3,3), N.Float32) R[0][0] = cos_gamma * cos_alpha - sin_gamma * cos_beta * sin_alpha R[0][1] = cos_gamma * sin_alpha + sin_gamma * cos_beta * cos_alpha R[0][2] = sin_gamma * sin_beta R[1][0] = -sin_gamma * cos_alpha - cos_gamma * cos_beta * sin_alpha R[1][1] = -sin_gamma * sin_alpha + cos_gamma * cos_beta * cos_alpha R[1][2] = cos_gamma * sin_beta R[2][0] = sin_beta * sin_alpha R[2][1] = -sin_beta * cos_alpha R[2][2] = cos_beta return R
def init_cyls(): # generate two circles in space as 13-gons, one rotated half a segment with # respect to the other these are used as cylinder ends [not quite true # anymore, see comments just below] slices = 13 circ1 = map((lambda n: n*2.0*pi/slices), range(slices+1)) circ2 = map((lambda a: a+pi/slices), circ1) drawing_globals.drum0 = drum0 = map((lambda a: (cos(a), sin(a), 0.0)), circ1) drum1 = map((lambda a: (cos(a), sin(a), 1.0)), circ2) drum1n = map((lambda a: (cos(a), sin(a), 0.0)), circ2) #grantham 20051213 I finally decided the look of the oddly twisted cylinder # bonds was not pretty enough, so I made a "drum2" which is just drum0 with # a 1.0 Z coordinate, a la drum1. #bruce 060609: this apparently introduced the bug of the drum1 end-cap of a # cylinder being "ragged" (letting empty space show through), which I fixed # by using drum2 for that cap rather than drum1. drum1 is no longer used # except as an intermediate value in the next few lines. drawing_globals.drum2 = drum2 = map((lambda a: (cos(a), sin(a), 1.0)), circ1) # This edge list zips up the "top" vertex and normal and then the "bottom" # vertex and normal. Thus each tuple in the sequence would be (vtop, ntop, # vbot, nbot) [grantham 20051213] # (bruce 051215 simplified the python usage in a way which should create the # same list.) drawing_globals.cylinderEdges = zip(drum0, drum0, drum2, drum0) circle = zip(drum0[:-1],drum0[1:],drum1[:-1]) +\ zip(drum1[:-1],drum0[1:],drum1[1:]) circlen = zip(drum0[:-1],drum0[1:],drum1n[:-1]) +\ zip(drum1n[:-1],drum0[1:],drum1n[1:]) drawing_globals.cap0n = (0.0, 0.0, -1.0) drawing_globals.cap1n = (0.0, 0.0, 1.0) drum0.reverse() return
def setUp(self): from opengltk.OpenGL import GL, GLUT print "GL imported from: ", GL.__file__ #print "Hit any key to quit." self.x = RandomArray.random( NUMDOTS) * 2 - 1 self.y = RandomArray.random( NUMDOTS) * 2 - 1 self.age = RandomArray.randint( 0,MAX_AGE, (NUMDOTS,)) move_length = 0.005 # 1.0 = screen width angle = 0 # in radians delta_angle = 0.2 # in radians self.move_x = move_length * Numeric.cos( angle) self.move_y = move_length * Numeric.sin( angle) self.halted = 0
def drawLines(self): # angle has to be provided in radians angle = self.angle self.circlePtsAngles = self.circlePtsAngles + angle self.circlePtsAngles = Numeric.remainder(self.circlePtsAngles, 2 * math.pi) xcoords = Numeric.cos(self.circlePtsAngles) xsin = Numeric.sin(self.circlePtsAngles) if self.orient == 'horizontal': w = self.innerbox[2] - self.innerbox[0] r = w / 2 c = self.innerbox[0] + r y1 = self.innerbox[1] y2 = self.innerbox[3] else: w = self.innerbox[3] - self.innerbox[1] r = w / 2 c = self.innerbox[1] + r y1 = self.innerbox[0] y2 = self.innerbox[2] cl = self.canvas.create_line setCoords = self.canvas.coords setOpt = self.canvas.itemconfigure pi2 = math.pi / 2. drawLines = 0 co = Numeric.take(xcoords, Numeric.nonzero(Numeric.greater_equal(xsin, 0.0))) co = Numeric.sort(co) co = [-1] + list(co) for i in range(len(co)): x = c - int(co[i] * r) if self.orient == 'horizontal': setCoords(self.linesIds[i], x, y1, x, y2) else: setCoords(self.linesIds[i], y1, x, y2, x) shopt = self.shadowLinesOptions[i] x = x + shopt[0] if self.orient == 'horizontal': setCoords(self.shLinesIds[i], x, y1, x, y2) else: setCoords(self.shLinesIds[i], y1, x, y2, x) setOpt(self.shLinesIds[i], fill=shopt[1], width=shopt[2])
def drawLines(self): # angle has to be provided in radians angle = self.angle self.circlePtsAngles = self.circlePtsAngles+angle self.circlePtsAngles = Numeric.remainder(self.circlePtsAngles, 2*math.pi) xcoords = Numeric.cos(self.circlePtsAngles) xsin = Numeric.sin(self.circlePtsAngles) if self.orient=='horizontal': w = self.innerbox[2] - self.innerbox[0] r = w/2 c = self.innerbox[0] + r y1 = self.innerbox[1] y2 = self.innerbox[3] else: w = self.innerbox[3] - self.innerbox[1] r = w/2 c = self.innerbox[1] + r y1 = self.innerbox[0] y2 = self.innerbox[2] cl = self.canvas.create_line setCoords = self.canvas.coords setOpt = self.canvas.itemconfigure pi2 = math.pi/2. drawLines = 0 co = Numeric.take(xcoords, Numeric.nonzero(Numeric.greater_equal(xsin, 0.0))) co = Numeric.sort(co) co = [-1]+list(co) for i in range(len(co)): x = c - int(co[i]*r) if self.orient=='horizontal': setCoords(self.linesIds[i], x, y1, x, y2) else: setCoords(self.linesIds[i], y1, x, y2, x) shopt = self.shadowLinesOptions[i] x = x + shopt[0] if self.orient=='horizontal': setCoords(self.shLinesIds[i], x, y1, x, y2) else: setCoords(self.shLinesIds[i], y1, x, y2, x) setOpt(self.shLinesIds[i], fill = shopt[1], width=shopt[2])
def __call__(self,**params): p=ParamOverrides(self,params) for template in p.plot_template: for sheet in topo.sim.objects(Sheet).values(): name=template.keys().pop(0) plot=make_template_plot(template,sheet.sheet_views,sheet.xdensity,sheet.bounds,p.normalize,name=template[name]) if plot: bitmap=plot.bitmap pylab.figure(figsize=(5,5)) isint=pylab.isinteractive() # Temporarily make non-interactive for plotting pylab.ioff() # Turn interactive mode off pylab.imshow(bitmap.image,origin='lower',interpolation='nearest') pylab.axis('off') for (t,pref,sel,c) in p.overlay: v = pylab.flipud(sheet.sheet_views[pref].view()[0]) if (t=='contours'): pylab.contour(v,[sel,sel],colors=c,linewidths=2) if (t=='arrows'): s = pylab.flipud(sheet.sheet_views[sel].view()[0]) scale=int(pylab.ceil(log10(len(v)))) X=pylab.array([x for x in xrange(len(v)/scale)]) v_sc=pylab.zeros((len(v)/scale,len(v)/scale)) s_sc=pylab.zeros((len(v)/scale,len(v)/scale)) for i in X: for j in X: v_sc[i][j]=v[scale*i][scale*j] s_sc[i][j]=s[scale*i][scale*j] pylab.quiver(scale*X,scale*X,-cos(2*pi*v_sc)*s_sc,-sin(2*pi*v_sc)*s_sc,color=c,edgecolors=c,minshaft=3,linewidths=1) p.title='%s overlaid with %s at time %s' %(plot.name,pref,topo.sim.timestr()) if isint: pylab.ion() p.filename_suffix="_"+sheet.name self._generate_figure(p)
def rotateAxis(theta, vector): """ Calculate a left multiplying rotation matrix that rotates theta rad around vector. Taken from: http://osdir.com/ml/python.bio.devel/2008-09/msg00084.html Example: >>> m=rotateAxis(pi, N.array([1,0,0])) @type theta: float @param theta: the rotation angle @type vector: L{Vector} @param vector: the rotation axis @return: The rotation matrix, a 3x3 Numeric array. """ vector = vector / N.linalg.norm(vector) x, y, z = vector c = N.cos(theta) s = N.sin(theta) t = 1 - c rot = N.zeros((3, 3), "d") # 1st row rot[0, 0] = t * x * x + c rot[0, 1] = t * x * y - s * z rot[0, 2] = t * x * z + s * y # 2nd row rot[1, 0] = t * x * y + s * z rot[1, 1] = t * y * y + c rot[1, 2] = t * y * z - s * x # 3rd row rot[2, 0] = t * x * z - s * y rot[2, 1] = t * y * z + s * x rot[2, 2] = t * z * z + c return rot
def rotateAxis(theta, vector): """ Calculate a left multiplying rotation matrix that rotates theta rad around vector. Taken from: http://osdir.com/ml/python.bio.devel/2008-09/msg00084.html Example: >>> m=rotateAxis(pi, N.array([1,0,0])) @type theta: float @param theta: the rotation angle @type vector: L{Vector} @param vector: the rotation axis @return: The rotation matrix, a 3x3 Numeric array. """ vector = vector / N.linalg.norm(vector) x,y,z=vector c=N.cos(theta) s=N.sin(theta) t=1-c rot=N.zeros((3,3), "d") # 1st row rot[0,0]=t*x*x+c rot[0,1]=t*x*y-s*z rot[0,2]=t*x*z+s*y # 2nd row rot[1,0]=t*x*y+s*z rot[1,1]=t*y*y+c rot[1,2]=t*y*z-s*x # 3rd row rot[2,0]=t*x*z-s*y rot[2,1]=t*y*z+s*x rot[2,2]=t*z*z+c return rot
def draw(self): p = self.parameters # shorthand if p.on: # calculate center center = VisionEgg._get_center(p.position,p.anchor,(p.radius, p.radius)) gl.glDisable(gl.GL_DEPTH_TEST) gl.glDisable(gl.GL_TEXTURE_2D) gl.glDisable(gl.GL_BLEND) if len(p.color)==3: gl.glColor3f(*p.color) elif len(p.color)==4: gl.glColor4f(*p.color) # Build filled circle from points # gl.glBegin(gl.GL_POINTS) # radius = int(math.ceil(p.radius)) # for i in range(-radius, radius): # for j in range(-radius, radius): # if(i * i + j * j < radius * radius): # gl.glVertex3f(p.position[0] + i, p.position[1] + j, 0.0) # gl.glEnd() # GL_POINTS # Build filled circle from triangles (this is typically faster # then the commented code above with the points) gl.glBegin(gl.GL_TRIANGLE_FAN) gl.glVertex3f(p.position[0], p.position[1], 0.0) angles = Numeric.arange(p.num_triangles)/float(p.num_triangles)*2.0*math.pi verts = Numeric.zeros( (p.num_triangles,2), Numeric.Float ) verts[:,0] = p.position[0] + p.radius * Numeric.cos(angles) verts[:,1] = p.position[1] + p.radius * Numeric.sin(angles) for i in range(verts.shape[0]): gl.glVertex2fv(verts[i]) gl.glVertex2fv(verts[0]) gl.glEnd() # GL_TRIANGLE_FAN if p.anti_aliasing: if not self._gave_alpha_warning: if len(p.color) > 3 and p.color[3] != 1.0: logger = logging.getLogger('VisionEgg.Arrow') logger.warning("The parameter anti_aliasing is " "set to true in the Arrow " "stimulus class, but the color " "parameter specifies an alpha " "value other than 1.0. To " "acheive anti-aliasing, ensure " "that the alpha value for the " "color parameter is 1.0.") self._gave_alpha_warning = 1 # We've already drawn a filled polygon (aliased), now redraw # the outline of the polygon (with anti-aliasing). (Using # GL_POLYGON_SMOOTH results in artifactual lines where # triangles were joined to create quad, at least on some OpenGL # implementations.) # Calculate coverage value for each pixel of outline # and store as alpha gl.glEnable(gl.GL_LINE_SMOOTH) # Now specify how to use the alpha value gl.glBlendFunc(gl.GL_SRC_ALPHA,gl.GL_ONE_MINUS_SRC_ALPHA) gl.glEnable(gl.GL_BLEND) # Draw a second polygon in line mode, so the edges are anti-aliased gl.glPolygonMode(gl.GL_FRONT_AND_BACK,gl.GL_LINE) gl.glBegin(gl.GL_TRIANGLE_FAN) gl.glVertex3f(p.position[0], p.position[1], 0.0) angles = Numeric.arange(p.num_triangles)/float(p.num_triangles)*2.0*math.pi verts = Numeric.zeros( (p.num_triangles,2), Numeric.Float ) verts[:,0] = p.position[0] + p.radius * Numeric.cos(angles) verts[:,1] = p.position[1] + p.radius * Numeric.sin(angles) for i in range(verts.shape[0]): gl.glVertex2fv(verts[i]) gl.glVertex2fv(verts[0]) gl.glEnd() # GL_TRIANGLE_FAN # Set the polygon mode back to fill mode gl.glPolygonMode(gl.GL_FRONT_AND_BACK,gl.GL_FILL) gl.glDisable(gl.GL_LINE_SMOOTH)
def draw(self): p = self.parameters # shorthand if p.on: # calculate center center = VisionEgg._get_center(p.position, p.anchor, (p.radius, p.radius)) gl.glDisable(gl.GL_DEPTH_TEST) gl.glDisable(gl.GL_TEXTURE_2D) gl.glDisable(gl.GL_BLEND) if len(p.color) == 3: gl.glColor3f(*p.color) elif len(p.color) == 4: gl.glColor4f(*p.color) # Build filled circle from points # gl.glBegin(gl.GL_POINTS) # radius = int(math.ceil(p.radius)) # for i in range(-radius, radius): # for j in range(-radius, radius): # if(i * i + j * j < radius * radius): # gl.glVertex3f(p.position[0] + i, p.position[1] + j, 0.0) # gl.glEnd() # GL_POINTS # Build filled circle from triangles (this is typically faster # then the commented code above with the points) gl.glBegin(gl.GL_TRIANGLE_FAN) gl.glVertex3f(p.position[0], p.position[1], 0.0) angles = Numeric.arange(p.num_triangles) / float( p.num_triangles) * 2.0 * math.pi verts = Numeric.zeros((p.num_triangles, 2), Numeric.Float) verts[:, 0] = p.position[0] + p.radius * Numeric.cos(angles) verts[:, 1] = p.position[1] + p.radius * Numeric.sin(angles) for i in range(verts.shape[0]): gl.glVertex2fv(verts[i]) gl.glVertex2fv(verts[0]) gl.glEnd() # GL_TRIANGLE_FAN if p.anti_aliasing: if not self._gave_alpha_warning: if len(p.color) > 3 and p.color[3] != 1.0: logger = logging.getLogger('VisionEgg.Arrow') logger.warning("The parameter anti_aliasing is " "set to true in the Arrow " "stimulus class, but the color " "parameter specifies an alpha " "value other than 1.0. To " "acheive anti-aliasing, ensure " "that the alpha value for the " "color parameter is 1.0.") self._gave_alpha_warning = 1 # We've already drawn a filled polygon (aliased), now redraw # the outline of the polygon (with anti-aliasing). (Using # GL_POLYGON_SMOOTH results in artifactual lines where # triangles were joined to create quad, at least on some OpenGL # implementations.) # Calculate coverage value for each pixel of outline # and store as alpha gl.glEnable(gl.GL_LINE_SMOOTH) # Now specify how to use the alpha value gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glEnable(gl.GL_BLEND) # Draw a second polygon in line mode, so the edges are anti-aliased gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE) gl.glBegin(gl.GL_TRIANGLE_FAN) gl.glVertex3f(p.position[0], p.position[1], 0.0) angles = Numeric.arange(p.num_triangles) / float( p.num_triangles) * 2.0 * math.pi verts = Numeric.zeros((p.num_triangles, 2), Numeric.Float) verts[:, 0] = p.position[0] + p.radius * Numeric.cos(angles) verts[:, 1] = p.position[1] + p.radius * Numeric.sin(angles) for i in range(verts.shape[0]): gl.glVertex2fv(verts[i]) gl.glVertex2fv(verts[0]) gl.glEnd() # GL_TRIANGLE_FAN # Set the polygon mode back to fill mode gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL) gl.glDisable(gl.GL_LINE_SMOOTH)
def addInternal(self, i, na, nb, nc, r, theta, phi): """ Add another point, given its internal coordinates. Once added via this routine, the cartesian coordinates for the point can be retrieved with getCartesian(). @param i: Index of the point being added. After this call, a call to getCartesian with this index value will succeed. Index values less than 4 are ignored. Index values should be presented here in sequence beginning with 4. @param na: Index value for point A. Point 'i' will be 'r' distance units from point A. @param nb: Index value for point B. Point 'i' will be located such that the angle i-A-B is 'theta' degrees. @param nc: Index value for point C. Point 'i' will be located such that the torsion angle i-A-B-C is 'torsion' degrees. @param r: Radial distance (in same units as resulting cartesian coordinates) between A and i. @param theta: Angle in degrees of i-A-B. @param phi: Torsion angle in degrees of i-A-B-C """ if (i < 4): return if (i != self._nextIndex): raise IndexError, "next index is %d not %r" % (self._nextIndex, i) cos_theta = cos(DEG2RAD * theta) xb = self._coords[nb][0] - self._coords[na][0] yb = self._coords[nb][1] - self._coords[na][1] zb = self._coords[nb][2] - self._coords[na][2] rba = 1.0 / sqrt(xb * xb + yb * yb + zb * zb) if abs(cos_theta) >= 0.999: # Linear case # Skip angles, just extend along A-B. rba = r * rba * cos_theta xqd = xb * rba yqd = yb * rba zqd = zb * rba else: xc = self._coords[nc][0] - self._coords[na][0] yc = self._coords[nc][1] - self._coords[na][1] zc = self._coords[nc][2] - self._coords[na][2] xyb = sqrt(xb * xb + yb * yb) inv = False if xyb < 0.001: # A-B points along the z axis. tmp = zc zc = -xc xc = tmp tmp = zb zb = -xb xb = tmp xyb = sqrt(xb * xb + yb * yb) inv = True costh = xb / xyb sinth = yb / xyb xpc = xc * costh + yc * sinth ypc = yc * costh - xc * sinth sinph = zb * rba cosph = sqrt(abs(1.0 - sinph * sinph)) xqa = xpc * cosph + zc * sinph zqa = zc * cosph - xpc * sinph yzc = sqrt(ypc * ypc + zqa * zqa) if yzc < 1e-8: coskh = 1.0 sinkh = 0.0 else: coskh = ypc / yzc sinkh = zqa / yzc sin_theta = sin(DEG2RAD * theta) sin_phi = -sin(DEG2RAD * phi) cos_phi = cos(DEG2RAD * phi) # Apply the bond length. xd = r * cos_theta yd = r * sin_theta * cos_phi zd = r * sin_theta * sin_phi # Compute the atom position using bond and torsional angles. ypd = yd * coskh - zd * sinkh zpd = zd * coskh + yd * sinkh xpd = xd * cosph - zpd * sinph zqd = zpd * cosph + xd * sinph xqd = xpd * costh - ypd * sinth yqd = ypd * costh + xpd * sinth if inv: tmp = -zqd zqd = xqd xqd = tmp self._coords[i][0] = xqd + self._coords[na][0] self._coords[i][1] = yqd + self._coords[na][1] self._coords[i][2] = zqd + self._coords[na][2] self._nextIndex = self._nextIndex + 1
def draw(self): # XXX This method is not speed-optimized. I just wrote it to # get the job done. (Nonetheless, it seems faster than the C # version commented out above.) p = self.parameters # shorthand if p.center is not None: if not hasattr(VisionEgg.config, "_GAVE_CENTER_DEPRECATION"): logger = logging.getLogger('VisionEgg.Dots') logger.warning("Specifying DotArea2D by deprecated " "'center' parameter deprecated. Use " "'position' parameter instead. (Allows " "use of 'anchor' parameter to set to " "other values.)") VisionEgg.config._GAVE_CENTER_DEPRECATION = 1 p.anchor = 'center' p.position = p.center[0], p.center[ 1] # copy values (don't copy ref to tuple) if p.on: # calculate center center = VisionEgg._get_center(p.position, p.anchor, p.size) if p.anti_aliasing: if len(p.color) == 4 and not self._gave_alpha_warning: if p.color[3] != 1.0: logger = logging.getLogger('VisionEgg.Dots') logger.warning("The parameter anti_aliasing is " "set to true in the DotArea2D " "stimulus class, but the color " "parameter specifies an alpha " "value other than 1.0. To " "acheive the best anti-aliasing, " "ensure that the alpha value for " "the color parameter is 1.0.") self._gave_alpha_warning = 1 gl.glEnable(gl.GL_POINT_SMOOTH) # allow max_alpha value to control blending gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) else: gl.glDisable(gl.GL_BLEND) now_sec = VisionEgg.time_func() if self.start_times_sec is not None: # compute extinct dots and generate new positions replace_indices = Numeric.nonzero( Numeric.greater(now_sec - self.start_times_sec, p.dot_lifespan_sec)) Numeric.put(self.start_times_sec, replace_indices, now_sec) new_x_positions = RandomArray.uniform(0.0, 1.0, (len(replace_indices), )) Numeric.put(self.x_positions, replace_indices, new_x_positions) new_y_positions = RandomArray.uniform(0.0, 1.0, (len(replace_indices), )) Numeric.put(self.y_positions, replace_indices, new_y_positions) new_random_directions_radians = RandomArray.uniform( 0.0, 2 * math.pi, (len(replace_indices), )) Numeric.put(self.random_directions_radians, replace_indices, new_random_directions_radians) else: # initialize dot extinction values to random (uniform) distribution self.start_times_sec = RandomArray.uniform( now_sec - p.dot_lifespan_sec, now_sec, (self.constant_parameters.num_dots, )) signal_num_dots = int( round(p.signal_fraction * self.constant_parameters.num_dots)) time_delta_sec = now_sec - self.last_time_sec self.last_time_sec = now_sec # reset for next loop x_increment_normalized = math.cos( p.signal_direction_deg / 180.0 * math.pi ) * p.velocity_pixels_per_sec / p.size[0] * time_delta_sec y_increment_normalized = -math.sin( p.signal_direction_deg / 180.0 * math.pi ) * p.velocity_pixels_per_sec / p.size[1] * time_delta_sec self.x_positions[:signal_num_dots] += x_increment_normalized self.y_positions[:signal_num_dots] += y_increment_normalized num_random_dots = self.constant_parameters.num_dots - signal_num_dots random_x_increment_normalized = Numeric.cos( self.random_directions_radians[signal_num_dots:] ) * p.velocity_pixels_per_sec / p.size[0] * time_delta_sec random_y_increment_normalized = -Numeric.sin( self.random_directions_radians[signal_num_dots:] ) * p.velocity_pixels_per_sec / p.size[1] * time_delta_sec self.x_positions[signal_num_dots:] += random_x_increment_normalized self.y_positions[signal_num_dots:] += random_y_increment_normalized self.x_positions = Numeric.fmod(self.x_positions, 1.0) # wrap self.y_positions = Numeric.fmod(self.y_positions, 1.0) self.x_positions = Numeric.fmod(self.x_positions + 1, 1.0) # wrap again for values < 1 self.y_positions = Numeric.fmod(self.y_positions + 1, 1.0) xs = (self.x_positions - 0.5) * p.size[0] + center[0] ys = (self.y_positions - 0.5) * p.size[1] + center[1] if len(p.color) == 3: gl.glColor3f(*p.color) elif len(p.color) == 4: gl.glColor4f(*p.color) gl.glPointSize(p.dot_size) # Clear the modeview matrix gl.glMatrixMode(gl.GL_MODELVIEW) gl.glPushMatrix() gl.glDisable(gl.GL_TEXTURE_2D) if p.depth is None: depth = 0.0 else: gl.glEnable(gl.GL_DEPTH_TEST) depth = p.depth zs = (depth, ) * len(xs) # make N tuple with repeat value of depth draw_dots(xs, ys, zs) if p.anti_aliasing: gl.glDisable(gl.GL_POINT_SMOOTH) # turn off gl.glPopMatrix()
def addInternal(self, i, na, nb, nc, r, theta, phi): """ Add another point, given its internal coordinates. Once added via this routine, the cartesian coordinates for the point can be retrieved with getCartesian(). @param i: Index of the point being added. After this call, a call to getCartesian with this index value will succeed. Index values less than 4 are ignored. Index values should be presented here in sequence beginning with 4. @param na: Index value for point A. Point 'i' will be 'r' distance units from point A. @param nb: Index value for point B. Point 'i' will be located such that the angle i-A-B is 'theta' degrees. @param nc: Index value for point C. Point 'i' will be located such that the torsion angle i-A-B-C is 'torsion' degrees. @param r: Radial distance (in same units as resulting cartesian coordinates) between A and i. @param theta: Angle in degrees of i-A-B. @param phi: Torsion angle in degrees of i-A-B-C """ if (i < 4): return if (i != self._nextIndex): raise IndexError, "next index is %d not %r" % (self._nextIndex, i) cos_theta = cos(DEG2RAD * theta) xb = self._coords[nb][0] - self._coords[na][0] yb = self._coords[nb][1] - self._coords[na][1] zb = self._coords[nb][2] - self._coords[na][2] rba = 1.0 / sqrt(xb*xb + yb*yb + zb*zb) if abs(cos_theta) >= 0.999: # Linear case # Skip angles, just extend along A-B. rba = r * rba * cos_theta xqd = xb * rba yqd = yb * rba zqd = zb * rba else: xc = self._coords[nc][0] - self._coords[na][0] yc = self._coords[nc][1] - self._coords[na][1] zc = self._coords[nc][2] - self._coords[na][2] xyb = sqrt(xb*xb + yb*yb) inv = False if xyb < 0.001: # A-B points along the z axis. tmp = zc zc = -xc xc = tmp tmp = zb zb = -xb xb = tmp xyb = sqrt(xb*xb + yb*yb) inv = True costh = xb / xyb sinth = yb / xyb xpc = xc * costh + yc * sinth ypc = yc * costh - xc * sinth sinph = zb * rba cosph = sqrt(abs(1.0- sinph * sinph)) xqa = xpc * cosph + zc * sinph zqa = zc * cosph - xpc * sinph yzc = sqrt(ypc * ypc + zqa * zqa) if yzc < 1e-8: coskh = 1.0 sinkh = 0.0 else: coskh = ypc / yzc sinkh = zqa / yzc sin_theta = sin(DEG2RAD * theta) sin_phi = -sin(DEG2RAD * phi) cos_phi = cos(DEG2RAD * phi) # Apply the bond length. xd = r * cos_theta yd = r * sin_theta * cos_phi zd = r * sin_theta * sin_phi # Compute the atom position using bond and torsional angles. ypd = yd * coskh - zd * sinkh zpd = zd * coskh + yd * sinkh xpd = xd * cosph - zpd * sinph zqd = zpd * cosph + xd * sinph xqd = xpd * costh - ypd * sinth yqd = ypd * costh + xpd * sinth if inv: tmp = -zqd zqd = xqd xqd = tmp self._coords[i][0] = xqd + self._coords[na][0] self._coords[i][1] = yqd + self._coords[na][1] self._coords[i][2] = zqd + self._coords[na][2] self._nextIndex = self._nextIndex + 1
def drawDnaRibbons(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = None, ribbon2_start_point = None, ribbon1_direction = None, ribbon2_direction = None, peakDeviationFromCenter = 9.5, ribbonThickness = 2.0, ribbon1Color = None, ribbon2Color = None, stepColor = None): """ Draw DNA ribbons where each strand is represented as a ribbon. DNA ribbons are drawn as sine waves with appropriate phase angles, with the phase angles computed in this method. @param endCenter1: Axis end 1 @type endCenter1: B{V} @param endCenter2: Axis end 2 @type endCenter2: B{V} @param basesPerTurn: Number of bases in a full turn. @type basesPerTurn: float @param duplexRise: Center to center distance between consecutive steps @type duplexRise: float @param glpaneScale: GLPane scale used in scaling arrow head drawing @type glpaneScale: float @param lineOfSightVector: Glpane lineOfSight vector, used to compute the the vector along the ladder step. @type: B{V} @param displayStyle: Rubberband display style (specified as an integer) see comment in the method below. See also GLPane.displayMode. @type displayStyle: int @param peakDeviationFromCenter: Distance of a peak from the axis Also known as 'Amplitude' of a sine wave. @type peakDeviationFromCenter: float @param ribbonThickness: Thickness of each of the the two ribbons @type ribbonThickness: float @param ribbon1Color: Color of ribbon1 @param ribbon2Color: Color of ribbon2 @see: B{DnaLineMode.Draw } (where it is used) for comments on color convention TODO: as of 2008-04-22 - Need more documentation - This method is long mainly because of a number of custom drawing See if that can be refactored e.g. methods like _drawRibbon1/strand1, drawRibbon2 / strand2 etc. - Further optimization / refactoring (low priority) """ #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) ###=== pointOnAxis = endCenter1 axial_shift_1 = V(0.0, 0.0, 0.0) # might be changed below axial_shift_2 = V(0.0, 0.0, 0.0) # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 numberOfBasesDrawn = 0 theta_offset = 0 x = 0 ### #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. Similarly, for ribbon_2, at x = 0, y = -6 # Putting these values will give use the phase_angle_2. # Note that for ribbon2_point, we subtract the value of equation [1] from # the point on axis. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) amplitude = peakDeviationFromCenter amplitudeVector = unitVectorAlongLadderStep * amplitude depthVector = unitDepthVector * amplitude # Note: to reduce the effect of perspective view on rung direction, # we could multiply depthVector by 0.1 or 0.01. But this would lessen # the depth realism of line/sphere intersections. [bruce 080216] ### if ribbon1_start_point is not None: ribbon1_point = ribbon1_start_point else: if ribbon2_start_point is not None: ribbon1_point = _get_ribbon_point_on_other_ribbon( ribbon2_start_point, ribbon2_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_1 = HALF_PI theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point and ribbon2_point ribbon1_point = pointOnAxis + \ amplitudeVector * sin(theta_ribbon_1) + \ depthVector * cos(theta_ribbon_1) ribbon1_direction = +1 drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = ribbon1_point, ribbon1_direction = ribbon1_direction, peakDeviationFromCenter = peakDeviationFromCenter, ribbonThickness = ribbonThickness, ribbon1Color = ribbon1Color, stepColor = stepColor) if ribbon2_start_point is not None: ribbon2_point = ribbon2_start_point else: if ribbon1_start_point is not None: ribbon2_point = _get_ribbon_point_on_other_ribbon( ribbon1_start_point, ribbon1_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_2 = asin(-6.0/(amplitude)) theta_ribbon_2 = (TWICE_PI * x / T) - phase_angle_ribbon_2 ribbon2_point = pointOnAxis - \ amplitudeVector * sin(theta_ribbon_2) + \ depthVector * cos(theta_ribbon_2) ribbon2_direction = -1 drawDnaSingleRibbon(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point = ribbon2_point, ribbon1_direction = ribbon2_direction, peakDeviationFromCenter = peakDeviationFromCenter, ribbonThickness = ribbonThickness, ribbon1Color = ribbon2Color, stepColor = stepColor) del vectorAlongLadderStep return
def setup_drawer(): """ Set up the usual constant display lists in the current OpenGL context. WARNING: THIS IS ONLY CORRECT IF ONLY ONE GL CONTEXT CONTAINS DISPLAY LISTS -- or more precisely, only the GL context this has last been called in (or one which shares its display lists) will work properly with the routines in drawer.py, since the allocated display list names are stored in globals set by this function, but in general those names might differ if this was called in different GL contexts. """ spherelistbase = glGenLists(_NUM_SPHERE_SIZES) sphereList = [] for i in range(_NUM_SPHERE_SIZES): sphereList += [spherelistbase+i] glNewList(sphereList[i], GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) # GL_LINE_LOOP to see edges stripVerts = getSphereTriStrips(i) for vertNorm in stripVerts: glNormal3fv(vertNorm) glVertex3fv(vertNorm) continue glEnd() glEndList() continue drawing_globals.sphereList = sphereList # Sphere triangle-strip vertices for each level of detail. # (Cache and re-use the work of making them.) # Can use in converter-wrappered calls like glVertexPointerfv, # but the python arrays are re-copied to C each time. sphereArrays = [] for i in range(_NUM_SPHERE_SIZES): sphereArrays += [getSphereTriStrips(i)] continue drawing_globals.sphereArrays = sphereArrays # Sphere glDrawArrays triangle-strip vertices for C calls. # (Cache and re-use the work of converting a C version.) # Used in thinly-wrappered calls like glVertexPointer. sphereCArrays = [] for i in range(_NUM_SPHERE_SIZES): CArray = numpy.array(sphereArrays[i], dtype = numpy.float32) sphereCArrays += [CArray] continue drawing_globals.sphereCArrays = sphereCArrays # Sphere indexed vertices. # (Cache and re-use the work of making the indexes.) # Can use in converter-wrappered calls like glDrawElementsui, # but the python arrays are re-copied to C each time. sphereElements = [] # Pairs of lists (index, verts) . for i in range(_NUM_SPHERE_SIZES): sphereElements += [indexVerts(sphereArrays[i], .0001)] continue drawing_globals.sphereElements = sphereElements # Sphere glDrawElements index and vertex arrays for C calls. sphereCIndexTypes = [] # numpy index unsigned types. sphereGLIndexTypes = [] # GL index types for drawElements. sphereCElements = [] # Pairs of numpy arrays (Cindex, Cverts) . for i in range(_NUM_SPHERE_SIZES): (index, verts) = sphereElements[i] if len(index) < 256: Ctype = numpy.uint8 GLtype = GL_UNSIGNED_BYTE else: Ctype = numpy.uint16 GLtype = GL_UNSIGNED_SHORT pass sphereCIndexTypes += [Ctype] sphereGLIndexTypes += [GLtype] sphereCIndex = numpy.array(index, dtype = Ctype) sphereCVerts = numpy.array(verts, dtype = numpy.float32) sphereCElements += [(sphereCIndex, sphereCVerts)] continue drawing_globals.sphereCIndexTypes = sphereCIndexTypes drawing_globals.sphereGLIndexTypes = sphereGLIndexTypes drawing_globals.sphereCElements = sphereCElements if glGetString(GL_EXTENSIONS).find("GL_ARB_vertex_buffer_object") >= 0: # A GLBufferObject version for glDrawArrays. sphereArrayVBOs = [] for i in range(_NUM_SPHERE_SIZES): vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCArrays[i], GL_STATIC_DRAW) sphereArrayVBOs += [vbo] continue drawing_globals.sphereArrayVBOs = sphereArrayVBOs # A GLBufferObject version for glDrawElements indexed verts. sphereElementVBOs = [] # Pairs of (IBO, VBO) for i in range(_NUM_SPHERE_SIZES): ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereCElements[i][0], GL_STATIC_DRAW) vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, sphereCElements[i][1], GL_STATIC_DRAW) sphereElementVBOs += [(ibo, vbo)] continue drawing_globals.sphereElementVBOs = sphereElementVBOs ibo.unbind() vbo.unbind() pass #bruce 060415 drawing_globals.wiresphere1list = wiresphere1list = glGenLists(1) glNewList(wiresphere1list, GL_COMPILE) didlines = {} # don't draw each triangle edge more than once def shoulddoline(v1,v2): # make sure not list (unhashable) or Numeric array (bug in __eq__) v1 = tuple(v1) v2 = tuple(v2) if (v1,v2) not in didlines: didlines[(v1,v2)] = didlines[(v2,v1)] = None return True return False def doline(v1,v2): if shoulddoline(v1,v2): glVertex3fv(v1) glVertex3fv(v2) return glBegin(GL_LINES) ocdec = getSphereTriangles(1) for tri in ocdec: #e Could probably optim this more, e.g. using a vertex array or VBO or # maybe GL_LINE_STRIP. doline(tri[0], tri[1]) doline(tri[1], tri[2]) doline(tri[2], tri[0]) glEnd() glEndList() drawing_globals.CylList = CylList = glGenLists(1) glNewList(CylList, GL_COMPILE) glBegin(GL_TRIANGLE_STRIP) for (vtop, ntop, vbot, nbot) in drawing_globals.cylinderEdges: glNormal3fv(nbot) glVertex3fv(vbot) glNormal3fv(ntop) glVertex3fv(vtop) glEnd() glEndList() drawing_globals.CapList = CapList = glGenLists(1) glNewList(CapList, GL_COMPILE) glNormal3fv(drawing_globals.cap0n) glBegin(GL_POLYGON) for p in drawing_globals.drum0: glVertex3fv(p) glEnd() glNormal3fv(drawing_globals.cap1n) glBegin(GL_POLYGON) #bruce 060609 fix "ragged edge" bug in this endcap: drum1 -> drum2 for p in drawing_globals.drum2: glVertex3fv(p) glEnd() glEndList() drawing_globals.diamondGridList = diamondGridList = glGenLists(1) glNewList(diamondGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.digrid: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.lonsGridList = lonsGridList = glGenLists(1) glNewList(lonsGridList, GL_COMPILE) glBegin(GL_LINES) for p in drawing_globals.lonsEdges: glVertex(p[0]) glVertex(p[1]) glEnd() glEndList() drawing_globals.CubeList = CubeList = glGenLists(1) glNewList(CubeList, GL_COMPILE) glBegin(GL_QUAD_STRIP) # note: CubeList has only 4 faces of the cube; only suitable for use in # wireframes; see also solidCubeList [bruce 051215 comment reporting # grantham 20051213 observation] glVertex((-1,-1,-1)) glVertex(( 1,-1,-1)) glVertex((-1, 1,-1)) glVertex(( 1, 1,-1)) glVertex((-1, 1, 1)) glVertex(( 1, 1, 1)) glVertex((-1,-1, 1)) glVertex(( 1,-1, 1)) glVertex((-1,-1,-1)) glVertex(( 1,-1,-1)) glEnd() glEndList() drawing_globals.solidCubeList = solidCubeList = glGenLists(1) glNewList(solidCubeList, GL_COMPILE) glBegin(GL_QUADS) for i in xrange(len(drawing_globals.cubeIndices)): avenormals = V(0,0,0) #bruce 060302 fixed normals for flat shading for j in xrange(4) : nTuple = tuple( drawing_globals.cubeNormals[drawing_globals.cubeIndices[i][j]]) avenormals += A(nTuple) avenormals = norm(avenormals) for j in xrange(4) : vTuple = tuple( drawing_globals.cubeVertices[drawing_globals.cubeIndices[i][j]]) #bruce 060302 made size compatible with glut.glutSolidCube(1.0) vTuple = A(vTuple) * 0.5 glNormal3fv(avenormals) glVertex3fv(vTuple) glEnd() glEndList() drawing_globals.rotSignList = rotSignList = glGenLists(1) glNewList(rotSignList, GL_COMPILE) glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS0n)): glVertex3fv(tuple(drawing_globals.rotS0n[ii])) glEnd() glBegin(GL_LINE_STRIP) for ii in xrange(len(drawing_globals.rotS1n)): glVertex3fv(tuple(drawing_globals.rotS1n[ii])) glEnd() glBegin(GL_TRIANGLES) for v in drawing_globals.arrow0Vertices + drawing_globals.arrow1Vertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearArrowList = linearArrowList = glGenLists(1) glNewList(linearArrowList, GL_COMPILE) glBegin(GL_TRIANGLES) for v in drawing_globals.linearArrowVertices: glVertex3f(v[0], v[1], v[2]) glEnd() glEndList() drawing_globals.linearLineList = linearLineList = glGenLists(1) glNewList(linearLineList, GL_COMPILE) glEnable(GL_LINE_SMOOTH) glBegin(GL_LINES) glVertex3f(0.0, 0.0, -drawing_globals.halfHeight) glVertex3f(0.0, 0.0, drawing_globals.halfHeight) glEnd() glDisable(GL_LINE_SMOOTH) glEndList() drawing_globals.circleList = circleList = glGenLists(1) glNewList(circleList, GL_COMPILE) glBegin(GL_LINE_LOOP) for ii in range(60): x = cos(ii*2.0*pi/60) y = sin(ii*2.0*pi/60) glVertex3f(x, y, 0.0) glEnd() glEndList() # piotr 080405 drawing_globals.filledCircleList = filledCircleList = glGenLists(1) glNewList(filledCircleList, GL_COMPILE) glBegin(GL_POLYGON) for ii in range(60): x = cos(ii*2.0*pi/60) y = sin(ii*2.0*pi/60) glVertex3f(x, y, 0.0) glEnd() glEndList() drawing_globals.lineCubeList = lineCubeList = glGenLists(1) glNewList(lineCubeList, GL_COMPILE) glBegin(GL_LINES) cvIndices = [0,1, 2,3, 4,5, 6,7, 0,3, 1,2, 5,6, 4,7, 0,4, 1,5, 2,6, 3,7] for i in cvIndices: glVertex3fv(tuple(drawing_globals.cubeVertices[i])) glEnd() glEndList() #initTexture('C:\\Huaicai\\atom\\temp\\newSample.png', 128,128) return # from setup_drawer
def getSphereTriStrips(level): steps = 2**level points = [] # Triangle Strip vertices o be returned. # Construct an icosahedron with two vertices at the North and South Poles, # +-1 on the Y axis, as you look toward the X-Y plane with the Z axis # pointing out at you. The "middle ring" vertices are all at the same # +-latitudes, on the intersection circles of the globe with a polar-axis # cylinder of the proper radius. # # The third "master vertex" of the icosahedron is placed on the X-Y plane, # which intersects the globe at the Greenwich Meridian (the semi-circle at # longitude 0, through Greenwich Observatory, 5 miles south-east of London.) # # The X (distance from the polar axis) and Y (height above the equatorial # plane) of the master vertex make a "golden rectangle", one unit high by # "phi" (1.6180339887498949) wide. We normalize this to put it on the # unit-radius sphere, and take the distance from the axis as the cylinder # radius used to generate the rest of the vertices of the two middle rings. # # Plotted on the globe, the master vertex (first vertex of the North ring) # is lat-long 31.72,0 due south of London in Africa, about 45 miles # south-southwest of Benoud, Algeria. The first vertex of the south ring is # rotated 1/10 of a circle east, at lat-long -31.72,36 in the south end of # the Indian Ocean, about 350 miles east-southeast of Durban, South Africa. # vert0 = norm(V(phi,1,0)) # Project the "master vertex" onto a unit sphere. cylRad = vert0[0] # Icos vertex distance from the Y axis. ringLat = atan2(vert0[1], vert0[0]) * degreesPerRadian # Latitude +-31.72 . # Basic triangle-strip icosahedron vertices. Start and end with the Poles. # Reflect the master vertex into the southern hemisphere and rotate 5 copies # to make the middle rings of 5 vertices at North and South latitudes. p2_5 = 2*pi / 5.0 # Simplify indexing by replicating the Poles, so everything is in fives. icosRings = [ 5 * [V(0.0, -1.0, 0.0)], # South Pole. # South ring, first edge *centered on* the Greenwich Meridian. [V(cylRad*cos((i-.5)*p2_5),-vert0[1], cylRad*sin((i-.5)*p2_5)) for i in range(5)], # North ring, first vertex *on* the Greenwich Meridian. [V(cylRad*cos(i*p2_5 ), vert0[1], cylRad*sin(i*p2_5)) for i in range(5)], 5 * [V(0.0, 1.0, 0.0)] ] # North Pole. # Three bands, going from bottom to top (South to North.) for band in range(3): lowerRing = icosRings[band] upperRing = icosRings[band+1] # Subdivide bands into sub-bands. When level == 0, steps == 1, # subBand == 0, and we get just the icosahedron out. (Really!) for subBand in range(steps): # Account for the tapering-in at the poles, making less points on # one edge of a sub-band than there are on the other edge. botOffset = 0 if band is 0: # South. botSteps = max(subBand, 1) # Don't divide by zero. topSteps = subBand + 1 # Collapse the *first* triangle of south sub-band bottom edges. botOffset = -1 elif band is 1: # Middle. botSteps = topSteps = steps else: # band is 2: North. botSteps = steps - subBand topSteps = max(steps - (subBand+1), 1) pass subBandSteps = max(botSteps, topSteps) # Do five segments, clockwise around the North Pole (East to West.) for seg in range(5): nextseg = (seg+1) % 5 # Wrap-around. # Interpolate ends of bottom & top edges of a sub-band segment. fractBot = float(subBand)/float(steps) fractTop = float(subBand+1)/float(steps) sbBotRight = fractBot * upperRing[seg] + \ (1.0-fractBot) * lowerRing[seg] sbTopRight = fractTop * upperRing[seg] + \ (1.0-fractTop) * lowerRing[seg] sbBotLeft = fractBot * upperRing[nextseg] + \ (1.0-fractBot) * lowerRing[nextseg] sbTopLeft = fractTop * upperRing[nextseg] + \ (1.0-fractTop) * lowerRing[nextseg] # Output the right end of the first segment of the sub-band. # We'll end up wrapping around to this same pair of points at # the left end of the last segment of the sub-band. if seg == 0: # Project verts from icosahedron faces onto the unit sphere. points += [norm(sbBotRight), norm(sbTopRight)] # Step across the sub-band edges from right to left, # stitching triangle pairs from their lower to upper edges. for step in range(1, subBandSteps+1): # Interpolate step point pairs along the sub-band edges. fractLower = float(step+botOffset)/float(botSteps) lower = fractLower * sbBotLeft + \ (1.0-fractLower) * sbBotRight # Collapse the *last* triangle of north sub-band top edges. fractUpper = float(min(step, topSteps))/float(topSteps) upper = fractUpper * sbTopLeft + \ (1.0-fractUpper) * sbTopRight # Output verts, projected from icos faces onto unit sphere. points += [norm(lower), norm(upper)] continue # step continue # seg continue # subBand continue # band return points
def __init__(self, x, y = None, z = None, w = None): if w is not None: # 4 numbers # [bruce comment 050518: note than ints are not turned to floats, # and no checking (of types or values) or normalization is done, # and that these arg names don't correspond to their meanings, # which are W,x,y,z (as documented) rather than x,y,z,w.] self.vec = V(x, y, z, w) elif z is not None: # three axis vectors # Just use first two # [bruce comments 050518: # - bugfix/optim: test z for None, not for truth value # (only fixes z = V(0,0,0) which is not allowed here anyway, so not very important) # - This case was not used until now, and was wrong for some or all inputs # (not just returning the inverse quat as I initially thought); # so I fixed it. # - The old code sometimes used 'z' but the new code never does # (except to decide to use this case, and when _DEBUG_QUATS to check the results). # Q(x, y, z) where x, y, and z are three orthonormal vectors # is the quaternion that rotates the standard axes into that # reference frame ##e could have a debug check for vlen(x), y,z, and ortho and right-handed... # but when this is false (due to caller bugs), the check_posns_near below should catch it. xfixer = Q( X_AXIS, x) y_axis_2 = xfixer.rot(Y_AXIS) yfixer = twistor( x, y_axis_2, y) res = xfixer res += yfixer # warning: modifies res -- xfixer is no longer what it was if _DEBUG_QUATS: check_posns_near( res.rot(X_AXIS), x, "x" ) check_posns_near( res.rot(Y_AXIS), y, "y" ) check_posns_near( res.rot(Z_AXIS), z, "z" ) self.vec = res.vec if _DEBUG_QUATS: res = self # sanity check check_posns_near( res.rot(X_AXIS), x, "sx" ) check_posns_near( res.rot(Y_AXIS), y, "sy" ) check_posns_near( res.rot(Z_AXIS), z, "sz" ) return # old code (incorrect and i think never called) commented out long ago, removed in rev. 1.27 [bruce 060228] elif type(y) in numTypes: # axis vector and angle [used often] v = (x / vlen(x)) * Numeric.sin(y * 0.5) self.vec = V(Numeric.cos(y * 0.5), v[0], v[1], v[2]) elif y is not None: # rotation between 2 vectors [used often] #bruce 050518 bugfix/optim: test y for None, not for truth value # (only fixes y = V(0,0,0) which is not allowed here anyway, so not very important) # [I didn't yet verify it does this in correct order; could do that from its use # in bonds.py or maybe the new indirect use in jigs.py (if I checked iadd too). ###@@@] #bruce 050730 bugfix: when x and y are very close to equal, original code treats them as opposite. # Rewriting it to fix that, though not yet in an ideal way (just returns identity). # Also, when they're close but not that close, original code might be numerically unstable. # I didn't fix that problem. x = norm(x) y = norm(y) dotxy = Numeric.dot(x, y) v = cross(x, y) vl = Numeric.dot(v, v) ** .5 if vl<0.000001: # x, y are very close, or very close to opposite, or one of them is zero if dotxy < 0: # close to opposite; treat as actually opposite (same as pre-050730 code) ax1 = cross(x, V(1, 0, 0)) ax2 = cross(x, V(0, 1, 0)) if vlen(ax1)>vlen(ax2): self.vec = norm(V(0, ax1[0],ax1[1],ax1[2])) else: self.vec = norm(V(0, ax2[0],ax2[1],ax2[2])) else: # very close, or one is zero -- we could pretend they're equal, but let's be a little # more accurate than that -- vl is sin of desired theta, so vl/2 is approximately sin(theta/2) # (##e could improve this further by using a better formula to relate sin(theta/2) to sin(theta)), # so formula for xyz part is v/vl * vl/2 == v/2 [bruce 050730] xyz = v / 2.0 sintheta2 = vl / 2.0 # sin(theta/2) costheta2 = (1 - sintheta2**2) ** .5 # cos(theta/2) self.vec = V(costheta2, xyz[0], xyz[1], xyz[2]) else: # old code's method is numerically unstable if abs(dotxy) is close to 1. I didn't fix this. # I also didn't review this code (unchanged from old code) for correctness. [bruce 050730] theta = math.acos(min(1.0, max(-1.0, dotxy))) if Numeric.dot(y, cross(x, v)) > 0.0: theta = 2.0 * math.pi - theta w = Numeric.cos(theta * 0.5) s = ((1 - w**2)**.5) / vl self.vec = V(w, v[0]*s, v[1]*s, v[2]*s) pass elif type(x) in numTypes: # just one number [#k is this ever used?] self.vec = V(1, 0, 0, 0) else: #bruce 050518 comment: a copy of the quat x, or of any length-4 sequence [both forms are used] self.vec = V(x[0], x[1], x[2], x[3]) return # from Q.__init__
def draw(self): # XXX This method is not speed-optimized. I just wrote it to # get the job done. (Nonetheless, it seems faster than the C # version commented out above.) p = self.parameters # shorthand if p.center is not None: if not hasattr(VisionEgg.config,"_GAVE_CENTER_DEPRECATION"): logger = logging.getLogger('VisionEgg.Dots') logger.warning("Specifying DotArea2D by deprecated " "'center' parameter deprecated. Use " "'position' parameter instead. (Allows " "use of 'anchor' parameter to set to " "other values.)") VisionEgg.config._GAVE_CENTER_DEPRECATION = 1 p.anchor = 'center' p.position = p.center[0], p.center[1] # copy values (don't copy ref to tuple) if p.on: # calculate center center = VisionEgg._get_center(p.position,p.anchor,p.size) if p.anti_aliasing: if len(p.color) == 4 and not self._gave_alpha_warning: if p.color[3] != 1.0: logger = logging.getLogger('VisionEgg.Dots') logger.warning("The parameter anti_aliasing is " "set to true in the DotArea2D " "stimulus class, but the color " "parameter specifies an alpha " "value other than 1.0. To " "acheive the best anti-aliasing, " "ensure that the alpha value for " "the color parameter is 1.0.") self._gave_alpha_warning = 1 gl.glEnable( gl.GL_POINT_SMOOTH ) # allow max_alpha value to control blending gl.glEnable( gl.GL_BLEND ) gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) else: gl.glDisable( gl.GL_BLEND ) now_sec = VisionEgg.time_func() if self.start_times_sec is not None: # compute extinct dots and generate new positions replace_indices = Numeric.nonzero( Numeric.greater( now_sec - self.start_times_sec, p.dot_lifespan_sec) ) Numeric.put( self.start_times_sec, replace_indices, now_sec ) new_x_positions = RandomArray.uniform(0.0,1.0, (len(replace_indices),)) Numeric.put( self.x_positions, replace_indices, new_x_positions ) new_y_positions = RandomArray.uniform(0.0,1.0, (len(replace_indices),)) Numeric.put( self.y_positions, replace_indices, new_y_positions ) new_random_directions_radians = RandomArray.uniform(0.0,2*math.pi, (len(replace_indices),)) Numeric.put( self.random_directions_radians, replace_indices, new_random_directions_radians ) else: # initialize dot extinction values to random (uniform) distribution self.start_times_sec = RandomArray.uniform( now_sec - p.dot_lifespan_sec, now_sec, (self.constant_parameters.num_dots,)) signal_num_dots = int(round(p.signal_fraction * self.constant_parameters.num_dots)) time_delta_sec = now_sec - self.last_time_sec self.last_time_sec = now_sec # reset for next loop x_increment_normalized = math.cos(p.signal_direction_deg/180.0*math.pi) * p.velocity_pixels_per_sec / p.size[0] * time_delta_sec y_increment_normalized = -math.sin(p.signal_direction_deg/180.0*math.pi) * p.velocity_pixels_per_sec / p.size[1] * time_delta_sec self.x_positions[:signal_num_dots] += x_increment_normalized self.y_positions[:signal_num_dots] += y_increment_normalized num_random_dots = self.constant_parameters.num_dots - signal_num_dots random_x_increment_normalized = Numeric.cos(self.random_directions_radians[signal_num_dots:]) * p.velocity_pixels_per_sec / p.size[0] * time_delta_sec random_y_increment_normalized = -Numeric.sin(self.random_directions_radians[signal_num_dots:]) * p.velocity_pixels_per_sec / p.size[1] * time_delta_sec self.x_positions[signal_num_dots:] += random_x_increment_normalized self.y_positions[signal_num_dots:] += random_y_increment_normalized self.x_positions = Numeric.fmod( self.x_positions, 1.0 ) # wrap self.y_positions = Numeric.fmod( self.y_positions, 1.0 ) self.x_positions = Numeric.fmod( self.x_positions+1, 1.0 ) # wrap again for values < 1 self.y_positions = Numeric.fmod( self.y_positions+1, 1.0 ) xs = (self.x_positions - 0.5) * p.size[0] + center[0] ys = (self.y_positions - 0.5) * p.size[1] + center[1] if len(p.color)==3: gl.glColor3f(*p.color) elif len(p.color)==4: gl.glColor4f(*p.color) gl.glPointSize(p.dot_size) # Clear the modeview matrix gl.glMatrixMode(gl.GL_MODELVIEW) gl.glPushMatrix() gl.glDisable(gl.GL_TEXTURE_2D) if p.depth is None: depth = 0.0 else: gl.glEnable(gl.GL_DEPTH_TEST) depth = p.depth zs = (depth,)*len(xs) # make N tuple with repeat value of depth draw_dots(xs,ys,zs) if p.anti_aliasing: gl.glDisable( gl.GL_POINT_SMOOTH ) # turn off gl.glPopMatrix()