Пример #1
0
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)
Пример #2
0
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)
Пример #3
0
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
Пример #4
0
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