def orbit(self, ref, axis, amt): """ Orbit the camera around an axis passing through a reerence point ref - this one orbits relative to the camera axes Currently, this function has the undesirable side-effect of possibly breaking the "camera.yz is parallel to the world Y=0 plane" constraint, and should not be used unless you know what you're doing. """ # Counter-rotate the camera. self.rotate(axis=axis, amt=amt) # Find the vector from the reference point to the camera vec = diff3D(ref, self.pos) # Rotate this vector around the axis if axis == X_AXIS: vec = rotate3D(vec, self.yz, amt) elif axis == Y_AXIS: vec = rotate3D(vec, self.up, amt) elif axis == Z_AXIS: vec = rotate3D(vec, self.vpn, -1 * amt) # Cacheable: Handled by setattr hook # Convert the vector into worldspace coordinates self.pos = add3D(ref, vec)
def makeStepVal(name, start, end, steps, locks=self._moveLock): """ This function gets called in event time, not right now! """ if name in locks: # Special case # We set =end on every frame if the end is a function (lambda). return None elif isinstance(end, (tuple, list)): # Assume these are 3D values. return div3D( diff3D(start, end), steps ) elif isinstance(end, FunctionType): # Evaluate lambdas here: # in clocktime this is the start of movement. # This can only lead to confusion. print "self:", self print "kwargs:", kwargs print "name:", name print "end:", end assert (False) else: return float(end - start) / steps
def absorbit(self, ref, axis, amt): """ Orbit the camera around an axis passing through a reference point ref. """ # Position the reference point in the proper plane with the camera # position. ref = ref[:axis] + (self.pos[axis],) + ref[axis + 1:] # Counter-rotate the camera. self.absrotate(axis=axis, amt=-1 * amt) delta = diff3D(ref, self.pos) r = dist3D(c=delta) # Cacheable: All these handled by setattr hook if axis == X_AXIS: theta = atan2(delta[Y_AXIS], delta[Z_AXIS]) theta = theta + (self.rotateSpeed * amt * pi / 180) self.pos = add3D(ref, (0, r * sin(theta), r * cos(theta))) elif axis == Y_AXIS: theta = atan2(delta[Z_AXIS], delta[X_AXIS]) theta = theta + (self.rotateSpeed * amt * pi / 180) self.pos = add3D(ref, (r * cos(theta), 0, r * sin(theta))) elif axis == Z_AXIS: theta = atan2(delta[X_AXIS], delta[Y_AXIS]) theta = theta + (-1 * self.rotateSpeed * amt * pi / 180) self.pos = add3D(ref, (r * sin(theta), r * cos(theta), 0))
def drawEdgeSelection(self, edge, alpha=0.4): """Draw a hilight around the edge.""" if isinstance(edge, SuperEdge): for subedge in edge.edgeOrder(): self.drawEdgeSelection(subedge) for vx in edge.bends: self.drawVertexSelection(vx) return ctx = self.graph.parent # Multiply points if snapping to grid # for Netcli (has no parent) showG = False if not ctx == None: if ctx.showGrid: showG = True if showG: srcpos = utilities.mult3D(edge.source.pos, ctx.spacing) tgtpos = utilities.mult3D(edge.target.pos, ctx.spacing) else: srcpos = edge.source.pos tgtpos = edge.target.pos diff = utilities.diff3D(srcpos, tgtpos) dist = utilities.dist3D(c=diff) # Avoid dividing by zero - # don't draw anything for zero-length edges if dist <= 0: return glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glPushMatrix() pigment = edge.color + (alpha,) glColor4f(*pigment) # Figure out radius boost factor x = max(log(40 * edge.radius, 10), 0) phi = acos(diff[Z_AXIS] / dist) * 180 / pi theta = atan2(diff[Y_AXIS], diff[X_AXIS]) * 180 / pi glTranslatef(*srcpos) glRotatef(theta, 0.0, 0.0, 1.0) glRotatef(phi, 0.0, 1.0, 0.0) gluQuadricOrientation(self.quad, GLU_OUTSIDE) gluQuadricTexture(self.quad, GL_TRUE) gluQuadricDrawStyle(self.quad, GLU_FILL) gluQuadricNormals(self.quad, GLU_SMOOTH) # glRotated(90, 1, 0, 0) gluCylinder(self.quad, edge.radius + x, edge.radius + x, dist, config.current['global:draw-edge-sides'], config.current['global:draw-edge-sides']) glPopMatrix() glDisable(GL_BLEND)
def arrangeStepwise(self, graph, vertices, newPos, duration, wait=0.0, tween=True): """ Arrange the vertices of the graph into a new layout specified by an indexed list of new positions newPos. The vertices will be positioned one at a time. """ assert (len(newPos) == len(vertices)) delay = float(duration) / len(vertices) from math import floor if tween: if delay > (1.0 / self.parent.fps): # No sense tweening faster than the frame rate can keep up stepsPerVert = int(floor(delay / (1.0 / self.parent.fps))) totalMove = [diff3D(a, b) for a, b in zip([x.pos for x in vertices], newPos)] partialMove = [div3D(x, stepsPerVert) for x in totalMove] else: tween = False accum = wait for i in range(len(vertices)): if tween: accum += delay / stepsPerVert for step in range(stepsPerVert - 1): self.post(accum, objects=( vertices[i], ), props=( ( 'pos', add3D(vertices[i].pos, mult3D(partialMove[i], (step + 1))), ), ), changeGraph=graph, ) accum += delay / stepsPerVert else: accum += delay self.post(accum, objects=( vertices[i], ), props=( ('pos', newPos[i]), ), changeGraph=graph, ) self.signal()
def __init__(self, ctx, vertex, snap, relative=False, updateHUD=None): Drawable.__init__(self) self.ctx = ctx self.vertex = vertex self.snap = snap self.relative = relative self.updateHUD = updateHUD if self.relative: startpos = self.vertex.pos startpoint = self.ctx.cursor.realPosition(self.ctx.camera) from utilities import diff3D self.offset = diff3D(startpoint, startpos)
def InputPos(self, pos): """ Translate an input device position for the cursor. """ from utilities import add3D, diff3D, mult3D self.move = False #Initialize jitter last position if self.first: self.lastPos = self.posMap(*pos) self.first = False if self.calibrate: mapped = self.posMap(*pos) offset = mult3D(mapped, self.posScale) self.posOrigin = offset self.calibrate = False if not self.manager.contexts.active: return # Translate the cursor position for use mapped = self.posMap(*pos) #Check for jitter for i in range(0, 3): dif = abs(mapped[i] - self.lastPos[i]) if dif < float(self.jitter): self.move = False or self.move else: self.move = True #Real Movement - not jitter! if self.move: offset = mult3D(mapped, self.posScale) offset = diff3D(self.posOrigin, offset) self.manager.contexts.active.cursor.inputPos(offset) self.manager.contexts.active.showCursor = True self.lastPos = mapped # Determine if cursor is below ground plane oldStatus = self.manager.contexts.active.HUDstatus if self.manager.contexts.active.graph.findGroundPlane() > \ self.manager.contexts.active.cursor.realPosition( \ self.manager.contexts.active.camera)[1]: self.manager.contexts.active.HUDstatus = "Cursor below groundplane" else: if oldStatus == "Cursor below groundplane": oldStatus = "" self.manager.contexts.active.HUDstatus = oldStatus
def perspCameraLookatMove(self, camera, newPos, fixLook, duration, wait=0.0): """ Moves the camera smoothly to a new position and orientation. If newLook is None, does not change the orientation of the camera. If newPos is None, does not change the position of the camera. """ from camera import Camera, OrthoCamera, X_AXIS, Y_AXIS, Z_AXIS assert (not isinstance(camera, OrthoCamera)) fixLook = self.normalizePos(fixLook) steps = int(duration * self.parent.fps) deltaPos = diff3D(camera.pos, newPos) stepPos = div3D(deltaPos, steps) accum = wait delay = 1.0 / self.parent.fps # Set up the animation for i in range(steps - 1): accum += delay self.post(accum, objects=(camera,), props=( ( 'pos', add3D(camera.pos, mult3D(stepPos, i + 1)) ), ( 'lookAt', fixLook), ), call=( ('absrotate', (Y_AXIS, stepYaw), {}), ('rotate', (X_AXIS, stepPitch), {}), ), ) # Finish up in the correct place accum += delay self.post(accum, objects=(camera,), props=( ('pos', newPos), ('lookAt', fixLook), ), ) self.signal()
def arrangeMorph(self, graph, vertices, newPos, duration, wait=0.0): """ Arrange the vertices of the graph into a new layout specified by an indexed list of new positions newPos. The vertices will be positioned simultaneously (smooth morph) """ assert (len(newPos) == len(vertices)) accum = wait steps = int(duration * self.parent.fps) delay = 1.0 / self.parent.fps d = [div3D(diff3D(a.pos, b), steps) for a, b in zip(vertices, newPos)] for i in range(steps - 1): accum += delay self.post(accum, objects=vertices, multiprops=( ( 'pos', [add3D(a.pos, mult3D(b, i + 1)) for a, b in zip(vertices, d)] ), ), changeGraph=graph, ) accum += delay self.post(accum, objects=vertices, multiprops=( ('pos', newPos), ), changeGraph=graph, ) self.signal()
def InputPos(self, pos): """ Translate an input device position for the cursor. """ from utilities import add3D, diff3D, mult3D #Camera jitter: no move to start self.move = False #Initiate jitter last position if self.first: self.lastPos = self.posMap(*pos) self.first = False print "jitter:", self.jitter if self.calibrate: mapped = self.posMap(*pos) offset = mult3D(mapped, self.posScale) self.posOrigin = offset self.calibrate = False if not self.manager.contexts.active: return # Translate the cursor position for use mapped = self.posMap(*pos) #Check for jitter for i in range(0, 3): dif = abs(mapped[i] - self.lastPos[i]) if dif < float(self.jitter): self.move = False or self.move else: self.move = True #Real Movement - not jitter! if self.move: offset = mult3D(mapped, self.posScale) offset = diff3D(self.posOrigin, offset) self.manager.contexts.active.camera.inputTrackPos(offset) self.lastPos = mapped
def drawHUD(self, camera, vertices, pos=None, status=''): from OpenGL.GLUT import glutStrokeCharacter, GLUT_STROKE_MONO_ROMAN view = glGetInteger(GL_VIEWPORT) if (view[1] != 0) or (view[3] != 0): # print "view = [", view[0], ",", view[1], ",", view[2], ",", view[3] # Switch to an orthogonal projection for drawing the HUD glDisable(GL_LIGHTING) glDisable(GL_DEPTH_TEST) glMatrixMode(GL_PROJECTION) glPushMatrix() glLoadIdentity() vheight = view[3] - view[1] vwidth = view[2] right = 100.0 top = float(vheight) / float(vwidth) * right glOrtho(0.0, right, 0.0, top, 0.0, 1.0) glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glEnable(GL_BLEND) glEnable(GL_LINE_SMOOTH) glEnable(GL_POLYGON_SMOOTH) # # Begin draw # from math import sin, cos, pi, atan2, acos, sqrt from utilities import diff3D, dist3D def circle(): for x in range(25): theta = x * 2 * pi / 24 glVertex3f(cos(theta), sin(theta), 0.0) def halfcircle(start, end): for x in range(start, end): theta = x * 2 * pi / 24 glVertex3f(cos(theta), sin(theta), 0.0) # Move into position to draw glLineWidth(1.0) glColor4f(1.0, 1.0, 1.0, 0.35) glPushMatrix() glTranslatef(89.0, 8.0, 0.001) glPushMatrix() glPushAttrib(GL_CURRENT_BIT) # Draw a circle to represent the XZ plane (bearing) glScalef(4.0, 4.0, 1.0) glBegin(GL_TRIANGLE_FAN) glVertex3f(0.0, 0.0, 0.0) circle() glEnd() # Draw the orientation of the camera glPushMatrix() glScalef(1.01, 1.01, 1.0) glColor4f(0.9, 0.9, 0.4, 0.9) glRotatef(180.0 * atan2(-1.0 * camera.vpn[Z_AXIS], camera.vpn[X_AXIS]) / pi, 0.0, 0.0, 1.0) glBegin(GL_TRIANGLE_FAN) glVertex3f(0.0, 0.0, 0.0) halfcircle(-2, 3) glEnd() glPopMatrix() # Draw the origin marker glPushMatrix() dOrigin = diff3D((0.0, 0.0, 0.0), camera.pos) glRotatef(270 - 180.0 * atan2(camera.pos[Z_AXIS], camera.pos[X_AXIS]) / pi - 90.0, 0.0, 0.0, 1.0) glColor4f(0.9, 0.2, 0.2, 0.95) glBegin(GL_TRIANGLES) glVertex3f(0.9, 0.0, 0.0) glVertex3f(1.1, -0.1, 0.0) glVertex3f(1.1, 0.1, 0.0) glEnd() glPopMatrix() # If there are vertices selected, draw vertex markers for v in vertices: glPushMatrix() dVertex = diff3D(v.pos, camera.pos) glRotatef(270 - 180.0 * atan2(dVertex[Z_AXIS], dVertex[X_AXIS]) / pi - 90.0, 0.0, 0.0, 1.0) glColor4f(0.2, 0.7, 0.9, 0.95) glBegin(GL_TRIANGLES) glVertex3f(0.9, 0.0, 0.0) glVertex3f(1.1, -0.1, 0.0) glVertex3f(1.1, 0.1, 0.0) glEnd() glPopMatrix() # Draw the X and Z axes on it glBegin(GL_LINE_STRIP) glColor3f(1.0, 0.5, 0.5) glVertex3f(-1.0, 0.0, 0.0) glVertex3f(-0.01, 0.0, 0.0) glColor3f(1.0, 0.0, 0.0) glVertex3f(0.0, 0.0, 0.0) glColor3f(0.5, 0.0, 0.0) glVertex3f(0.01, 0.0, 0.0) glVertex3f(1.0, 0.0, 0.0) glEnd() glBegin(GL_LINE_STRIP) glColor3f(0.5, 0.5, 1.0) glVertex3f(0.0, 1.0, 0.0) glVertex3f(0.0, 0.01, 0.0) glColor3f(0.0, 0.0, 1.0) glVertex3f(0.0, 0.0, 0.0) glColor3f(0.0, 0.0, 0.5) glVertex3f(0.0, -0.01, 0.0) glVertex3f(0.0, -1.0, 0.0) glEnd() glPopAttrib() # Done drawing XZ plane # Draw a half-circle to represent elevation glPushAttrib(GL_CURRENT_BIT) glTranslatef(2.2, 0.0, 0.0) glBegin(GL_TRIANGLE_FAN) halfcircle(6, 19) glEnd() # Draw the orientation of the camera glPushMatrix() glScalef(1.01, 1.01, 1.0) glColor4f(0.9, 0.9, 0.4, 0.9) glRotatef(90.0 + 180.0 * acos(utilities.dot_product(camera.vpn, (0.0, 1.0, 0.0))) / pi, 0.0, 0.0, 1.0) glBegin(GL_TRIANGLE_FAN) glVertex3f(0.0, 0.0, 0.0) halfcircle(-2, 3) glEnd() glPopMatrix() # Draw the zero-elevation line glBegin(GL_LINES) glColor4f(0.0, 0.0, 0.0, 1.0) glVertex3f(-1.0, 0.0, 0.0) glVertex3f(0.0, 0.0, 0.0) glEnd() # Draw the origin marker glPushMatrix() dOrigin = diff3D(camera.pos, (0.0, 0.0, 0.0)) dist = dist3D(c=dOrigin) glRotatef(90.0 + 180.0 * acos(utilities.dot_product(dOrigin, (0.0, 1.0, 0.0)) / dist) / pi, 0.0, 0.0, 1.0) glColor4f(0.9, 0.2, 0.2, 0.95) glBegin(GL_TRIANGLES) glVertex3f(0.9, 0.0, 0.0) glVertex3f(1.1, -0.1, 0.0) glVertex3f(1.1, 0.1, 0.0) glEnd() glPopMatrix() # If there are vertices selected, draw vertex markers for v in vertices: glPushMatrix() dVertex = diff3D(v.pos, camera.pos) dist = dist3D(c=dVertex) glRotatef(270.0 - 180.0 * acos(utilities.dot_product(dVertex, (0.0, 1.0, 0.0)) / dist) / pi, 0.0, 0.0, 1.0) glColor4f(0.2, 0.7, 0.9, 0.95) glBegin(GL_TRIANGLES) glVertex3f(0.9, 0.0, 0.0) glVertex3f(1.1, -0.1, 0.0) glVertex3f(1.1, 0.1, 0.0) glEnd() glPopMatrix() # Clean up glPopMatrix() glPopAttrib() # Coordinates - if _pos_ is specified, draw that, # otherwise use the current position of the camera. if pos == None: pos = camera.pos glPushAttrib(GL_CURRENT_BIT) glPushMatrix() glTranslatef(-8.0, -7.0, 0.0) glScalef(0.009, 0.016, 1.0) # Draw the background box glBegin(GL_QUADS) glVertex3f(0.0, -40.0, 0.0) glVertex3f(2300.0, -40.0, 0.0) glVertex3f(2300.0, 140.0, 0.0) glVertex3f(0.0, 140.0, 0.0) glEnd() # Draw the text xS = ('%.1f' % pos[0]).rjust(6) + ' ' yS = ('%.1f' % pos[1]).rjust(6) + ' ' zS = ('%.1f' % pos[2]).rjust(6) + ' ' glLineWidth(1.7) glColor4f(0.56, 0.0, 0.0, 0.9) for c in xS: glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, ord(c)) glColor4f(0.0, 0.56, 0.0, 0.9) for c in yS: glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, ord(c)) glColor4f(0.0, 0.0, 0.56, 0.9) for c in zS: glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, ord(c)) glPopAttrib() glPopMatrix() glPopMatrix() # # end draw # # # now draw HUD status line # if status: glColor4f(1.0, 1.0, 1.0, 0.25) glPushMatrix() glTranslatef(0.0, 1.0, 0.001) glPushMatrix() glScalef(0.009, 0.016, 1.0) glBegin(GL_QUADS) glVertex3f(0.0, -40.0, 0.0) glVertex3f(5000.0, -40.0, 0.0) glVertex3f(5000.0, 140.0, 0.0) glVertex3f(0.0, 140.0, 0.0) glEnd() glLineWidth(1.4) glColor4f(0.56, 0.0, 0.0, 0.9) # Add some space before the first character glTranslatef(200.0, 0.0, 0.0) for c in status: glutStrokeCharacter(GLUT_STROKE_ROMAN, ord(c)) glPopMatrix() glPopMatrix() # # end HUD statusline draw # glPopMatrix() glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glEnable(GL_LIGHTING) glEnable(GL_DEPTH_TEST)
def arrangeSpring(context, axes=(X_AXIS, Z_AXIS, Y_AXIS), sync=None, edgeTension=0.85, edgeLength=3.0, useAttrEdgeK=False, invAttrEdgeK=False, useAttrEdgeLen=False, invAttrEdgeLen=False): """ Arrange the vertices of the graph according to a force-directed spring model. """ EPSILON = 0.1 JITTER = EPSILON / 8 TIMEINC = 0.7 from utilities import jitterForce, repulseForce, springForce, diff3D, add3D from graph import DummyVertex balanced = False # # Set vertex mass # # XXX# Dummy vertices are 1/4 the mass of regular vertices. vxMass = dict([(v.id, (pi / 3.0, 2.0 * pi / 3.0)[isinstance(v, DummyVertex)]) for v in context.graph.vertices]) #XXX# Scale by volume #vxMass = [4.0 * pi * v.radius * v.radius * v.radius / 3.0 for v in context.graph.vertices] # # Set vertex charge # vxCharge = dict([(v.id, 1.0) for v in context.graph.vertices]) # # Set edge spring tensions # # The edgeTension parameter is specified in the range [0.0, 1.0]. # Adjust it to be within reasonable bounds. if edgeTension > 1.0 or edgeTension < 0.0: raise GraphError, "Edge tension must be in the range [0.0, 1.0]" # 0.13 is practical (minimizing oscillations) # 0.11 is good (visibility separation) edgeTension = edgeTension * 0.15 if useAttrEdgeK: edgeK = context.graph.normalizeFromEdges( \ max=edgeTension, min=0.001, inv=invAttrEdgeK, \ valFunc=lambda e: float(e.attribute), \ failError="Some edge attributes could not be converted to float values for tension.") else: # not useAttrEdgeK edgeK = dict([((e.source.id, e.target.id), edgeTension) for e in context.graph.edges]) # # Set edge ideal length # # The edgeLength parameter must be >0.0 if edgeLength <= 0.0: raise GraphError, "Edge length must be >0.0" if useAttrEdgeLen: edgeLen = context.graph.normalizeFromEdges( \ max=edgeLength, min=0.0, inv=invAttrEdgeLen, \ valFunc=lambda e: float(e.attribute), \ failError="Some edge attributes could not be converted to float values for length.") else: edgeLen = dict([((e.source.id, e.target.id), edgeLength) for e in context.graph.edges]) # # Set pass number # I = 0 # Set changed flag now - if we set it after, then it's possible # that we could bail out without change flag getting set. context.graph.change() # # Do at least 2 passes to ensure that coincident vertices # get jittered apart. # while not balanced or I < 2: I = I + 1 # Initialize the force on each vertex to 0. vxForceSum = dict([(x.id, (0.0, 0.0, 0.0)) for x in context.graph.vertices]) balanced = True for v_num in range(len(context.graph.vertices)): v = context.graph.vertices[v_num] # Edges for u in v.nearestVertices(): if u == v: continue edges = context.graph.findEdgeBetween(u, v) for e in edges: F = springForce(diff3D(v.pos, u.pos), Kuv=edgeK[(e.source.id, e.target.id)], Luv=edgeLen[(e.source.id, e.target.id)], j=JITTER) vxForceSum[v.id] = add3D(vxForceSum[v.id], F) # Vertices for u in context.graph.vertices: if u == v: continue F = repulseForce(diff3D(u.pos, v.pos), q1=vxCharge[u.id], q2=vxCharge[v.id], Cuv=300, j=JITTER) vxForceSum[v.id] = add3D(vxForceSum[v.id], F) # Jitter F = jitterForce(JITTER) vxForceSum[v.id] = add3D(vxForceSum[v.id], F) # Tether F = springForce(diff3D(v.pos, (0.0, 0.0, 0.0)), Kuv=0.005, Luv=1.0, j=JITTER) vxForceSum[v.id] = add3D(vxForceSum[v.id], F) if abs(vxForceSum[v.id][0]) > EPSILON and X_AXIS in axes or \ abs(vxForceSum[v.id][1]) > EPSILON and Y_AXIS in axes or \ abs(vxForceSum[v.id][2]) > EPSILON and Z_AXIS in axes: balanced = False # Now we have the force on each vertex. # Act on them. for v in context.graph.vertices: vel = ((X_AXIS in axes) * vxForceSum[v.id][0] * TIMEINC / vxMass[v.id], (Y_AXIS in axes) * vxForceSum[v.id][1] * TIMEINC / vxMass[v.id], (Z_AXIS in axes) * vxForceSum[v.id][2] * TIMEINC / vxMass[v.id]) v.pos = add3D(v.pos, vel) if sync: # Because we're saving calls by referring to the vertices directly, # we have to set the change flag here, before we sync. context.graph.change() sync() context.graph.change() return I
def drawEdge(self, edge, alpha=1.0): """ draw an edge in 3D. """ # Superedge drawing is a no-op - all the parts will already have been # drawn. if isinstance(edge, SuperEdge): return if config.current['global:enable-anaglyph']: pigment = (1.0, 1.0, 1.0, alpha) else: pigment = edge.color + (alpha,) glColor4f(*pigment) # For Netcli (has no parent) ctx = self.graph.parent showG = False if not ctx == None: if ctx.showGrid: showG = True if showG: srcpos = utilities.mult3D(edge.source.pos, ctx.spacing) tgtpos = utilities.mult3D(edge.target.pos, ctx.spacing) else: srcpos = edge.source.pos tgtpos = edge.target.pos if config.current['global:draw-edge-cylinders']: diff = utilities.diff3D(srcpos, tgtpos) dist = utilities.dist3D(c=diff) # Avoid dividing by zero - # don't draw anything for zero-length edges if dist <= 0: return glPushMatrix() phi = acos(diff[Z_AXIS] / dist) * 180 / pi theta = atan2(diff[Y_AXIS], diff[X_AXIS]) * 180 / pi glTranslatef(*srcpos) glRotatef(theta, 0.0, 0.0, 1.0) glRotatef(phi, 0.0, 1.0, 0.0) gluQuadricOrientation(self.quad, GLU_OUTSIDE) gluQuadricTexture(self.quad, GL_TRUE) gluQuadricDrawStyle(self.quad, GLU_FILL) gluQuadricNormals(self.quad, GLU_SMOOTH) #glRotated(90, 1, 0, 0) gluCylinder(self.quad, edge.radius, edge.radius, dist, config.current['global:draw-edge-sides'], config.current['global:draw-edge-sides']) glPopMatrix() else: # not drawing edges as cylinders glDisable(GL_LIGHTING) glEnable(GL_LINE_SMOOTH) glLineWidth(config.current['global:draw-edge-linewidth']) glBegin(GL_LINES) glVertex3f(srcpos[0], srcpos[1], srcpos[2]) glVertex3f(tgtpos[0], tgtpos[1], tgtpos[2]) glEnd() glEnable(GL_LIGHTING)
def perspCameraMove(self, camera, newPos=None, newLook=None, duration=1.0, wait=0.0): """ Moves the camera smoothly to a new position and orientation. If newLook is None, does not change the orientation of the camera. If newPos is None, does not change the position of the camera. """ from camera import Camera, OrthoCamera, X_AXIS, Y_AXIS, Z_AXIS assert (not isinstance(camera, OrthoCamera)) newCam = Camera() if newPos != None: newCam.pos = self.normalizePos(newPos) else: newCam.pos = camera.pos if newLook != None: newCam.lookAt = self.normalizePos(newLook) else: newCam.lookAt = camera.lookAt steps = int(duration * self.parent.fps) (oldTheta, oldPhi) = camera.polar() (newTheta, newPhi) = newCam.polar() deltaYaw = newTheta - oldTheta deltaPitch = newPhi - oldPhi deltaPos = diff3D(camera.pos, newCam.pos) # Check to make sure we're coming around the short side if deltaYaw > 180.0: deltaYaw = deltaYaw - 360.0 elif deltaYaw < -180.0: deltaYaw = deltaYaw + 360.0 print "DeltaYaw", deltaYaw stepYaw = deltaYaw / steps stepPitch = deltaPitch / steps stepPos = div3D(deltaPos, steps) accum = wait delay = 1.0 / self.parent.fps # Set up the animation for i in range(steps - 1): accum += delay self.post(accum, objects=( camera, ), props=( ( 'pos', add3D(camera.pos, mult3D(stepPos, i + 1)), ), ), call=( ('absrotate', (Y_AXIS, stepYaw), {}), ('rotate', (X_AXIS, stepPitch), {}), ), ) # Finish up in the correct place accum += delay self.post(accum, objects=(camera,), props=( ('pos', newCam.pos), ('lookAt', newCam.lookAt), ), ) self.signal()