def drawDnaLadder(endCenter1, endCenter2, duplexRise, glpaneScale, lineOfSightVector, ladderWidth = 17.0, beamThickness = 2.0, beam1Color = None, beam2Color = None, stepColor = None ): """ Draws the DNA in a ladder display where each strand is represented as a ladder beam and each step represents duplex rise. @param endCenter1: Ladder center at end 1 @type endCenter1: B{V} @param endCenter2: Ladder center at end 2 @type endCenter2: B{V} @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 ladderWidth: width of the ladder @type ladderWidth: float @param beamThickness: Thickness of the two ladder beams @type beamThickness: float @param beam1Color: Color of beam1 @param beam2Color: Color of beam2 @see: B{DnaLineMode.Draw } (where it is used) for comments on color convention """ ladderLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ladderLength is atleast equal to the duplexRise. # i.e. do the drawing only when there are atleast two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint if ladderLength < duplexRise: return if beam1Color is None: beam1Color = env.prefs[DarkBackgroundContrastColor_prefs_key] if beam2Color is None: beam2Color = env.prefs[DarkBackgroundContrastColor_prefs_key] if stepColor is None: stepColor = env.prefs[DarkBackgroundContrastColor_prefs_key] unitVector = norm(endCenter2 - endCenter1) glDisable(GL_LIGHTING) glPushMatrix() glTranslatef(endCenter1[0], endCenter1[1], endCenter1[2]) pointOnAxis = V(0, 0, 0) vectorAlongLadderStep = cross(-lineOfSightVector, unitVector) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) ladderBeam1Point = pointOnAxis + unitVectorAlongLadderStep*0.5*ladderWidth ladderBeam2Point = pointOnAxis - unitVectorAlongLadderStep*0.5*ladderWidth #Following limits the arrowHead Size to the given value. When you zoom out, #the rest of ladder drawing becomes smaller (expected) and the following #check ensures that the arrowheads are drawn proportinately. # (Not using a 'constant' to do this as using glpaneScale gives better #results) if glpaneScale > 40: arrowDrawingScale = 40 else: arrowDrawingScale = glpaneScale #Draw the arrow head on beam1 drawArrowHead(beam2Color, ladderBeam2Point, arrowDrawingScale, -unitVectorAlongLadderStep, - unitVector) x = 0.0 while x < ladderLength: drawPoint(stepColor, pointOnAxis) previousPoint = pointOnAxis previousLadderBeam1Point = ladderBeam1Point previousLadderBeam2Point = ladderBeam2Point pointOnAxis = pointOnAxis + unitVector*duplexRise x += duplexRise ladderBeam1Point = previousPoint + \ unitVectorAlongLadderStep*0.5*ladderWidth ladderBeam2Point = previousPoint - \ unitVectorAlongLadderStep*0.5*ladderWidth if previousLadderBeam1Point: drawline(beam1Color, previousLadderBeam1Point, ladderBeam1Point, width = beamThickness, isSmooth = True ) drawline(beam2Color, previousLadderBeam2Point, ladderBeam2Point, width = beamThickness, isSmooth = True ) drawline(stepColor, ladderBeam1Point, ladderBeam2Point) drawArrowHead(beam1Color, ladderBeam1Point, arrowDrawingScale, unitVectorAlongLadderStep, unitVector) glPopMatrix() glEnable(GL_LIGHTING)
def drawDnaLadder(endCenter1, endCenter2, duplexRise, glpaneScale, lineOfSightVector, ladderWidth=17.0, beamThickness=2.0, beam1Color=None, beam2Color=None, stepColor=None): """ Draws the DNA in a ladder display where each strand is represented as a ladder beam and each step represents duplex rise. @param endCenter1: Ladder center at end 1 @type endCenter1: B{V} @param endCenter2: Ladder center at end 2 @type endCenter2: B{V} @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 ladderWidth: width of the ladder @type ladderWidth: float @param beamThickness: Thickness of the two ladder beams @type beamThickness: float @param beam1Color: Color of beam1 @param beam2Color: Color of beam2 @see: B{DnaLineMode.Draw } (where it is used) for comments on color convention """ ladderLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ladderLength is atleast equal to the duplexRise. # i.e. do the drawing only when there are atleast two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint if ladderLength < duplexRise: return if beam1Color is None: beam1Color = env.prefs[DarkBackgroundContrastColor_prefs_key] if beam2Color is None: beam2Color = env.prefs[DarkBackgroundContrastColor_prefs_key] if stepColor is None: stepColor = env.prefs[DarkBackgroundContrastColor_prefs_key] unitVector = norm(endCenter2 - endCenter1) glDisable(GL_LIGHTING) glPushMatrix() glTranslatef(endCenter1[0], endCenter1[1], endCenter1[2]) pointOnAxis = V(0, 0, 0) vectorAlongLadderStep = cross(-lineOfSightVector, unitVector) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) ladderBeam1Point = pointOnAxis + unitVectorAlongLadderStep * 0.5 * ladderWidth ladderBeam2Point = pointOnAxis - unitVectorAlongLadderStep * 0.5 * ladderWidth #Following limits the arrowHead Size to the given value. When you zoom out, #the rest of ladder drawing becomes smaller (expected) and the following #check ensures that the arrowheads are drawn proportinately. # (Not using a 'constant' to do this as using glpaneScale gives better #results) if glpaneScale > 40: arrowDrawingScale = 40 else: arrowDrawingScale = glpaneScale #Draw the arrow head on beam1 drawArrowHead(beam2Color, ladderBeam2Point, arrowDrawingScale, -unitVectorAlongLadderStep, -unitVector) x = 0.0 while x < ladderLength: drawPoint(stepColor, pointOnAxis) previousPoint = pointOnAxis previousLadderBeam1Point = ladderBeam1Point previousLadderBeam2Point = ladderBeam2Point pointOnAxis = pointOnAxis + unitVector * duplexRise x += duplexRise ladderBeam1Point = previousPoint + \ unitVectorAlongLadderStep*0.5*ladderWidth ladderBeam2Point = previousPoint - \ unitVectorAlongLadderStep*0.5*ladderWidth if previousLadderBeam1Point: drawline(beam1Color, previousLadderBeam1Point, ladderBeam1Point, width=beamThickness, isSmooth=True) drawline(beam2Color, previousLadderBeam2Point, ladderBeam2Point, width=beamThickness, isSmooth=True) drawline(stepColor, ladderBeam1Point, ladderBeam2Point) drawArrowHead(beam1Color, ladderBeam1Point, arrowDrawingScale, unitVectorAlongLadderStep, unitVector) glPopMatrix() glEnable(GL_LIGHTING)
def 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 = None, ribbon1_direction = None, peakDeviationFromCenter = 9.5, ribbonThickness = 2.0, ribbon1Color = None, stepColor = None): """ @see: drawDnaRibbons (method in this file) @see: DnaStrand_GraphicsMode._drawHandles() """ if 0: # debug code, useful to see where the argument points are located # [bruce 080422] draw_debug_text(glpane, endCenter1, "endCenter1") draw_debug_text(glpane, endCenter2, "endCenter2") draw_debug_text(glpane, ribbon1_start_point, "ribbon1_start_point") #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 if stepColor is None: stepColor = env.prefs[DarkBackgroundContrastColor_prefs_key] 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. It also means the dna duplex axis can be determined # below from the two endpoints. if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) glDisable(GL_LIGHTING) ##glPushMatrix() ##glTranslatef(endCenter1[0], endCenter1[1], endCenter1[2]) ##pointOnAxis = V(0, 0, 0) pointOnAxis = endCenter1 axial_shift = V(0.0, 0.0, 0.0) # might be changed below # [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 if ribbon1_start_point is not None: # [revise the meaning of these values to give the coordinate system # with the right phase in which to draw the ribbon. # bruce 080422 bugfix] vectorAlongLadderStep0 = ribbon1_start_point - endCenter1 # note: this might not be perpendicular to duplex axis. # fix by subtracting off the parallel component. # but add the difference back to every point below. vectorAlongLadderStep = vectorAlongLadderStep0 - \ dot( unitVectorAlongLength, vectorAlongLadderStep0 ) * unitVectorAlongLength axial_shift = (vectorAlongLadderStep0 - vectorAlongLadderStep) # note: even using this, there is still a small glitch in the # location of the first drawn sphere vs. the ribbon point... don't # know why. [bruce 080422] unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 pass del vectorAlongLadderStep ###=== #Following limits the arrowHead Size to the given value. When you zoom out, #the rest of ladder drawing becomes smaller (expected) and the following #check ensures that the arrowheads are drawn proportionately. # (Not using a 'constant' to do this as using glpaneScale gives better #results) if glpaneScale > 40: arrowDrawingScale = 40 else: arrowDrawingScale = glpaneScale #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. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) numberOfBasesDrawn = 0 theta_offset = 0 ## phase_angle_ribbon_1 = HALF_PI ## theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point # [note: might not be needed, since identical to first point # computed during loop, but present code uses it to initialize # previous_ribbon1_point during loop [bruce 080422 comment]] ribbon1_point = _compute_ribbon_point(pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset ) while x < ribbonLength: #Draw the axis point. drawPoint(stepColor, pointOnAxis) previousPointOnAxis = pointOnAxis previous_ribbon1_point = ribbon1_point ribbon1_point = _compute_ribbon_point(pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset ) if x == duplexRise and ribbon1_direction == -1: # For ribbon_2 we need to draw an arrow head for y at x = 0. # To do this, we need the 'next ribbon_2' point in order to # compute the appropriate vectors. So when x = duplexRise, the # previous_ribbon2_point is nothing but y at x = 0. arrowLengthVector2 = norm(ribbon1_point - previous_ribbon1_point ) arrowHeightVector2 = cross(-lineOfSightVector, arrowLengthVector2) drawArrowHead( ribbon1Color, previous_ribbon1_point, arrowDrawingScale, -arrowHeightVector2, -arrowLengthVector2) # Draw sphere over previous_ribbon1_point and not ribbon1_point. # This is so we don't draw a sphere over the last point on ribbon1 # (instead, it is drawn as an arrowhead after the while loop). drawsphere(ribbon1Color, previous_ribbon1_point, SPHERE_RADIUS, SPHERE_DRAWLEVEL, opacity = SPHERE_OPACITY) drawline(stepColor, pointOnAxis, ribbon1_point) #Increment the pointOnAxis and x pointOnAxis = pointOnAxis + unitVectorAlongLength * duplexRise x += duplexRise numberOfBasesDrawn += 1 if previous_ribbon1_point: drawline(ribbon1Color, previous_ribbon1_point, ribbon1_point, width = ribbonThickness, isSmooth = True ) arrowLengthVector1 = norm(ribbon1_point - previous_ribbon1_point) arrowHeightVector1 = cross(-lineOfSightVector, arrowLengthVector1) pass continue # while x < ribbonLength if ribbon1_direction == 1: #Arrow head for endpoint of ribbon_1. drawArrowHead(ribbon1Color, ribbon1_point, arrowDrawingScale, arrowHeightVector1, arrowLengthVector1) #The second axis endpoint of the dna is drawn as a transparent sphere. #Note that the second axis endpoint is NOT NECESSARILY endCenter2 . In fact # those two are equal only at the ladder steps. In other case (when the # ladder step is not completed), the endCenter1 is ahead of the #'second axis endpoint of the dna' drawsphere(AXIS_ENDPOINT_SPHERE_COLOR, previousPointOnAxis, AXIS_ENDPOINT_SPHERE_RADIUS, AXIS_ENDPOINT_SPHERE_DRAWLEVEL, opacity = AXIS_ENDPOINT_SPHERE_OPACITY) ##glPopMatrix() glEnable(GL_LIGHTING) return # from drawDnaSingleRibbon