예제 #1
0
    def draw(self, glpane, offset = V(0,0,0), color = None, info = {}): # modified copy of superclass draw method
        "draw our spheres (in practice we'll need to extend this for different sets...)"
##        self.radius_multiplier = 1.0 # this might be changed by certain subclass's process_optional_info method
##        self.process_optional_info(info) # might reset instvars that affect following code... (kluge?)
        color = color or self.color
        ##detailLevel = 0 # just an icosahedron
        detailLevel = 1 # easier to click on this way
        ##radius = 0.33 # the one we store might be too large? no, i guess it's ok.
        #e (i might prefer an octahedron, or a miniature-convex-hull-of-extrude-unit)
        offset = offset + self.origin
        radius_multiplier = self.radius_multiplier
        special_pos = self.special_pos # patched in ###nim?
        special_pos = special_pos + offset #k?? or just self.origin??
        special_color = self.special_color # default is used
##        count = 0
        for (pos,radius,info) in self.handles:
            radius *= radius_multiplier
            pos = pos + offset
            dist = vlen(special_pos - pos)
            if dist <= radius:
                color2 = ave_colors( 1.0 - dist/radius, special_color, color )
##                count += 1
            else:
                color2 = color
            ## experiment 050218: add alpha factor to color
            color2 = tuple(color2) + (0.25,)
            drawsphere(color2, pos, radius, detailLevel)
##        self.color2_count = count # kluge, probably not used since should equal nbonds
        return
    def _drawSpecialIndicators(self):
        final_crossover_atoms_dict = self._crossoverSite_marker.get_final_crossover_atoms_dict()
        for atm in final_crossover_atoms_dict.values():
            sphere_radius = max(1.20*atm.drawing_radius(), 
                                SPHERE_RADIUS)
            drawsphere(darkgreen, 
                       atm.posn(), 
                       sphere_radius,
                       SPHERE_DRAWLEVEL,
                       opacity = SPHERE_OPACITY) 

        if self.DEBUG_DRAW_ALL_POTENTIAL_CROSSOVER_SITES:
            atom_dict = self._crossoverSite_marker.get_base_orientation_indicator_dict()
            for atm in atom_dict.values():
                drawsphere(darkred, 
                           atm.posn(), 
                           1.5,
                           SPHERE_DRAWLEVEL,
                           opacity = SPHERE_OPACITY) 

        if self.DEBUG_DRAW_PLANE_NORMALS:    
            self._DEBUG_drawPlaneNormals()

        if self.DEBUG_DRAW_AVERAGE_CENTER_PAIRS_OF_POTENTIAL_CROSSOVERS:
            self._DEBUG_draw_avg_centerpairs_of_potential_crossovers()
    def Draw(self):

        # TODO: also super draw, for model, axes, etc?
        
        color = self.command.cylinderColor
        length = cylinder_height()
##        if self.command.cylinderVertical:
##            direction = DY
##        else:
##            direction = DX
        direction = self.command.direction
        end1 = ORIGIN - direction * length/2.0
        end2 = ORIGIN + direction * length/2.0
        radius = self.command.cylinderWidth / 2.0
        capped = True
        drawcylinder(color, end1, end2, radius, capped)

        if cylinder_round_caps():
            detailLevel = 2
            drawsphere( color, end1, radius, detailLevel)
            drawsphere( color, end2, radius, detailLevel)

        if self.command.widthHandleEnabled:
            self.command.widthHandle.draw()

        super(_test_connectWithState_GM, self).Draw() # added this, bruce 071022
        return
예제 #4
0
def drawPeptideTrace(alphaCarbonProteinChunk):
    """
    Draws a protein backbone trace using atoms stored in
    I{alphaCarbonProteinChunk}.

    @param alphaCarbonProteinChunk: a special (temporary) chunk that contains
                                    only the alpha carbon atoms in the peptide
                                    backbone
    @param alphaCarbonProteinChunk: Chunk

    @see PeptideLine_GraphicsMode.Draw_other(), PeptideGenerator.make_aligned()
    """

    if alphaCarbonProteinChunk and alphaCarbonProteinChunk.atoms:
        last_pos = None
        atomitems = alphaCarbonProteinChunk.atoms.items()
        atomitems.sort()
        alphaCarbonAtomsList = [atom for (key, atom) in atomitems]

        for atom in alphaCarbonAtomsList:
            drawsphere(blue, atom.posn(), 0.2, 1)
            if last_pos:
                drawline(gray, last_pos, atom.posn(), width=2)
            last_pos = atom.posn()
            pass
        pass
    return
예제 #5
0
    def Draw_other(self):
        """
        """
        _superclass_for_GM.Draw_other(self)

        #This fixes NFR bug  2803
        #Don't draw the Dna rubberband line if the cursor is over the confirmation
        #corner. But make sure to call superclass.Draw_other method before doing this 
        #check because we need to draw the rest of the model in the graphics 
        #mode!. @see: DnaLineMode_GM.Draw_other() which does similar thing to not 
        #draw the rubberband line when the cursor is on the confirmation corner
        handler = self.o.mouse_event_handler
        if handler is not None and handler is self._ccinstance:
            ##### REVIEW:
            #
            # 1. This is probably incorrect in principle, as a way of
            # deciding what to draw. The mouse event handling methods
            # should set an attribute which directly specifies whether
            # the next call of Draw_other (or other Draw methods)
            # should draw the rubberband line or not.
            # (Or which affects the value of an access method, e.g.
            #  something like self.should_draw_rubberband_lines().)
            #
            # 2. Why is update_cursor called here? Any call of update_cursor
            # inside a specific Draw method seems suspicious.
            #
            # 3. This needs refactoring to merge with common code in its
            # subclass DnaLineMode_GM, and to consider doing the same
            # thing in its other 3 subclasses.
            #
            # [bruce 090310 comments]
            self.update_cursor()
            return

        if self.endPoint2 is not None:

            if self.endPoint1:
                drawsphere(self.endPoint1_sphereColor, 
                           self.endPoint1, 
                           STARTPOINT_SPHERE_RADIUS,
                           STARTPOINT_SPHERE_DRAWLEVEL,
                           opacity = self.endPoint1_sphereOpacity
                           )            
            drawline(env.prefs[DarkBackgroundContrastColor_prefs_key], 
                     self.endPoint1, 
                     self.endPoint2,
                     width = self.rubberband_line_width,
                     dashEnabled = True)         

            self._drawSnapReferenceLines()

            if self._ok_to_render_cursor_text:                           
                self._drawCursorText()
예제 #6
0
 def drawchunk_realtime(self, glpane, chunk, highlighted=False):
     if chunk.protein:
         for aa in chunk.protein.get_amino_acids():
             if chunk.protein.is_expanded(aa):
                 for atom in aa.get_atom_list():
                     pos1 = chunk.abs_to_base(atom.posn())
                     color = atom.drawing_color()
                     drawsphere(color, pos1, 0.25, 1)
                     for bond in atom.bonds:
                         if atom == bond.atom1:
                             pos2 = chunk.abs_to_base(bond.atom2.posn())
                             drawcylinder(color, pos1, pos1 + 0.5*(pos2 - pos1), 0.2, 1)
                         else:
                             pos2 = chunk.abs_to_base(bond.atom1.posn())
                             drawcylinder(color, pos1 + 0.5*(pos2 - pos1), pos1, 0.2, 1)
     return
 def _drawTags(self):
     """
     Overrides _superClass._drawTags()
     for self._tagPositions.
     @see: self.drawTag()
     @see: GraphicsMode._drawTags()
     @see: class PM_SelectionWidget
     """ 
    
     if self._tagPositions:
         for point in self._tagPositions:          
             drawsphere(banana, 
                        point, 
                        SPHERE_RADIUS_FOR_TAGS ,
                        SPHERE_DRAWLEVEL,
                        opacity = SPHERE_OPACITY)
예제 #8
0
    def draw(self, glpane, offset = V(0,0,0), color = None, info = {}): # this code is copied/modified into a subclass, sorry
        """
        draw our spheres (in practice we'll need to extend this for different sets...)
        """
##        self.radius_multiplier = 1.0 # this might be changed by certain subclass's process_optional_info method
##        self.process_optional_info(info) # might reset instvars that affect following code... (kluge?)
        color = color or self.color
        ##detailLevel = 0 # just an icosahedron
        detailLevel = 1 # easier to click on this way
        ##radius = 0.33 # the one we store might be too large? no, i guess it's ok.
        #e (i might prefer an octahedron, or a miniature-convex-hull-of-extrude-unit)
        offset = offset + self.origin
        radius_multiplier = self.radius_multiplier
        color = tuple(color) + (1.0,) ## experiment 050218: alpha factor #bruce 051230 moved outside of loop to fix bug 1250
        for (pos,radius,info) in self.handles:
            drawsphere(color, pos + offset, radius * radius_multiplier, detailLevel)
예제 #9
0
            def primCSDL(centers, radii, colors):
                if not doTransforms:
                    csdl = ColorSortedDisplayList() # Transformless.
                else:
                    # Test pattern for TransformControl usage - vertical columns
                    # of TC domains, separated by X coord of first center point.
                    # Chunking will be visible when transforms are changed.
                    xCoord = centers[0][0] - start_pos[0] # Negate centering X.
                    xPercent = (xCoord /
                                (nSpheres + nSpheres/10 +
                                 nSpheres/100 - 1 + (nSpheres <= 1)))
                    xTenth = int(xPercent * 10 + .5)
                    csdl = ColorSortedDisplayList(TCs[xTenth % numTCs])
                    pass

                # Test selection using the CSDL glname.
                ColorSorter.pushName(csdl.glname)
                ColorSorter.start(glpane, csdl)
                for (color, center, radius) in zip(colors, centers, radii):
                    if not doCylinders:
                        # Through ColorSorter to the sphere primitive buffer...
                        drawsphere(color, center, radius,
                                   DRAWSPHERE_DETAIL_LEVEL)
                    else:
                        # Through ColorSorter to cylinder primitive buffer...
                        if not drawing_globals.cylinderShader_available():
                            print "warning: not cylinderShader_available(), error is likely:"
                        if (True and  # Whether to do tapered shader-cylinders.
                            # Display List cylinders don't support taper.
                            glpane.glprefs.cylinderShader_desired()):
                            ###cylRad = (radius/2.0, (.75-radius)/2.0)
                            cylRad = (radius/1.5 - .167, .3 - radius/1.5)
                        else:
                            cylRad = radius/2.0
                            pass
                        endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5)
                        drawcylinder(color, center, endPt2, cylRad)
                        global test_endpoints
                        test_endpoints += [(center, endPt2)]
                        pass
                    continue
                ColorSorter.popName()
                ColorSorter.finish(draw_now = True)

                test_DrawingSet.addCSDL(csdl)
                return csdl
예제 #10
0
 def __init__(self, x, y, n):
     self.csdl = ColorSortedDisplayList()
     # draw into it, based on x, y, n
     ColorSorter.start(None, self.csdl)
     for i in range(n):
         z = i - (_NUM_SPHERES_PER_CSDL - 1) / 2.0
         color = (random.uniform(0.2, 0.8),
                  0,
                  random.uniform(0.2, 0.8))
         pos = (x, y, z)
         radius = 0.25 # 0.5 would be touching the next ones
         drawsphere(color,
                    pos,
                    radius,
                    2 ## DRAWSPHERE_DETAIL_LEVEL
          )
     ColorSorter.finish(draw_now = False)
     return
    def _drawTags(self):
        """
        Overrides _superClass._drawTags()
        for self._tagPositions.
        @see: self.drawTag()
        @see: GraphicsMode._drawTags()
        @see: class PM_SelectionWidget
        """ 
        if 0:
            #see method for details. Used for debugging only
            self._DEBUG_Flag_EndPoint1_ofDnaSegments()

        if self._tagPositions:
            for point in self._tagPositions:          
                drawsphere(silver, 
                           point, 
                           SPHERE_RADIUS,
                           SPHERE_DRAWLEVEL,
                           opacity = SPHERE_OPACITY)
    def _DEBUG_Flag_EndPoint1_ofDnaSegments(self):
        """
        Temporary method that draws a sphere to indicate the endPoint1 
        of each segment being resized. Used for debugging a bug in 
        computing average end points for the resize handles.
        """
        if not self.command:
            return 

        endPoints_1 = []
         
        for segment in self.command.getResizeSegmentList():
            e1, e2 = segment.getAxisEndPoints()
            if e1 is not None:
                endPoints_1.append(e1)
        for end1 in endPoints_1:
            drawsphere(lighterblue, 
                       end1, 
                       SPHERE_RADIUS,
                       SPHERE_DRAWLEVEL,
                       opacity = 1.0)
예제 #13
0
    def Draw(self):
        """
        Draw method for this temporary mode. 
        """
        _superclass_for_GM.Draw(self)

        #This fixes NFR bug  2803
        #Don't draw the Dna rubberband line if the cursor is over the confirmation
        #corner. But make sure to call superclass.Draw method before doing this 
        #check because we need to draw the rest of the model in the graphics 
        #mode!. @see: DnaLineMode_GM.Draw() which does similar thing to not 
        #draw the rubberband line when the cursor is on the confirmation corner
        handler = self.o.mouse_event_handler
        if handler is not None and handler is self._ccinstance:
            self.update_cursor()
            return

        if self.endPoint2 is not None:

            if self.endPoint1:
                drawsphere(self.endPoint1_sphereColor, 
                           self.endPoint1, 
                           STARTPOINT_SPHERE_RADIUS,
                           STARTPOINT_SPHERE_DRAWLEVEL,
                           opacity = self.endPoint1_sphereOpacity
                           )            
            drawline(self.rubberband_line_color, 
                     self.endPoint1, 
                     self.endPoint2,
                     width = self.rubberband_line_width,
                     dashEnabled = True)         

            self._drawSnapReferenceLines()

            if self._ok_to_render_cursor_text:                           
                self._drawCursorText()
예제 #14
0
 def _cellDraw(self, color, p0, p1):
     hasSinglet = False
     if type(p1) == type((1,)):
         v1 = p1[0]
         hasSinglet = True
     else:
         v1 = p1
     if self.dispMode == "Tubes":
         drawcylinder(color, p0, v1, 0.2)
     else:
         drawsphere(color, p0, 0.5, 1)
         if hasSinglet:
             drawsphere(color, v1, 0.2, 1)
         else:
             drawsphere(color, v1, 0.5, 1)
         drawline(white, p0, v1)
예제 #15
0
    def _bondDraw(self, color, p0, p1, carbonAt):
        if self.dispMode == "Tubes":
            drawcylinder(color, p0, p1, 0.2)
        else:
            if carbonAt < 0:
                drawsphere(color, p0, 0.5, 1)
                drawsphere(color, p1, 0.5, 1)
            elif carbonAt == 0:
                drawsphere(color, p0, 0.5, 1)
                drawsphere(color, p1, 0.2, 1)
            elif carbonAt == 1:
                drawsphere(color, p0, 0.2, 1)
                drawsphere(color, p1, 0.5, 1)

            drawline(white, p0, p1)
예제 #16
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
예제 #17
0
def test_drawing(glpane, initOnly=False):
    """
    When TEST_DRAWING is enabled at the start of
    graphics/widgets/GLPane_rendering_methods.py,
    and when TestGraphics_Command is run (see its documentation
    for various ways to do that),
    this file is loaded and GLPane.paintGL() calls the
    test_drawing() function instead of the usual body of paintGL().
    """
    # WARNING: this duplicates some code with test_Draw_model().

    # Load the sphere shaders if needed.
    global _USE_SHADERS
    if _USE_SHADERS:
        if not drawing_globals.test_sphereShader:
            print "test_drawing: Loading sphere shaders."

            try:
                from graphics.drawing.gl_shaders import GLSphereShaderObject
                drawing_globals.test_sphereShader = GLSphereShaderObject()
                ##### REVIEW: is this compatible with my refactoring in drawing_globals?
                # If not, use of Test Graphics Performance command might cause subsequent
                # bugs in other code. Ideally we'd call the new methods that encapsulate
                # this, to setup shaders. [bruce 090304 comment]

                print "test_drawing: Sphere-shader initialization is complete.\n"
            except:
                _USE_SHADERS = False
                print "test_drawing: Exception while loading sphere shaders, will reraise and not try again"
                raise
            pass

    global start_pos, first_time

    if first_time:
        # Set up the viewing scale, but then let interactive zooming work.
        glpane.scale = nSpheres * .6
        pass

    # This same function gets called to set up for drawing, and to draw.
    if not initOnly:
        glpane._setup_modelview()
        glpane._setup_projection()
        ##glpane._compute_frustum_planes()

        glClearColor(64.0, 64.0, 64.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
                | GL_STENCIL_BUFFER_BIT)
        ##glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )

        glMatrixMode(GL_MODELVIEW)
        pass

    global test_csdl, test_dl, test_dls, test_ibo, test_vbo, test_spheres
    global test_DrawingSet, test_endpoints, test_Object

    # See below for test case descriptions and timings on a MacBook Pro.
    # The Qt event toploop in NE1 tops out at about 60 frames-per-second.

    # NE1 with test toploop, single CSDL per draw (test case 1)
    # . 17,424 spheres (132x132, through the color sorter) 4.8 FPS
    #   Russ 080919: More recently, 12.2 FPS.
    # . Level 2 spheres have 9 triangles x 20 faces, 162 distinct vertices,
    #   visited on the average 2.3 times, giving 384 tri-strip vertices.
    # . 17,424 spheres is 6.7 million tri-strip vertices.  (6,690,816)
    if testCase == 1:
        if test_csdl is None:
            print("Test case 1, %d^2 spheres\n  %s." %
                  (nSpheres, "ColorSorter"))

            test_csdl = ColorSortedDisplayList()
            ColorSorter.start(None, test_csdl)
            drawsphere(
                [0.5, 0.5, 0.5],  # color
                [0.0, 0.0, 0.0],  # pos
                .5,  # radius
                DRAWSPHERE_DETAIL_LEVEL,
                testloop=nSpheres)
            ColorSorter.finish(draw_now=True)
            pass
        else:
            test_csdl.draw()
        pass

    # NE1 with test toploop, single display list per draw (test case 2)
    # . 10,000 spheres (all drawing modes) 17.5 FPS
    # . 17,424 spheres (132x132, manual display list) 11.1 FPS
    # . 40,000 spheres (mode 5 - VBO/IBO spheres from DL's) 2.2 FPS
    # . 40,000 spheres (mode 6 - Sphere shaders from DL's) 2.5 FPS
    # . 90,000 spheres (all drawing modes) 1.1 FPS
    elif testCase == 2:
        if test_dl is None:
            print("Test case 2, %d^2 spheres\n  %s." %
                  (nSpheres, "One display list calling primitive dl's"))

            test_dl = glGenLists(1)
            glNewList(test_dl, GL_COMPILE_AND_EXECUTE)
            drawsphere_worker_loop((
                [0.0, 0.0, 0.0],  # pos
                .5,  # radius
                DRAWSPHERE_DETAIL_LEVEL,
                nSpheres))
            glEndList()
            pass
        else:
            glColor3i(127, 127, 127)
            glCallList(test_dl)
        pass

    # NE1 with test toploop, one big chunk VBO/IBO of box quads (test case 3)
    # .  17,424 spheres (1 box/shader draw call) 43.7 FPS
    # .  17,424 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 57.7 FPS
    # .  40,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 56.7 FPS
    # .  90,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 52.7 FPS
    # . 160,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 41.4 FPS
    # . 250,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 27.0 FPS
    elif int(testCase) == 3:
        doTransforms = False
        if test_spheres is None:
            print("Test case 3, %d^2 spheres\n  %s." %
                  (nSpheres, "One big VBO/IBO chunk buffer"))
            if testCase == 3.1:
                print("Sub-test 3.1, animate partial updates.")
            elif testCase == 3.2:
                print("Sub-test 3.2, animate partial updates" +
                      " w/ C per-chunk array buffering.")
            elif testCase == 3.3:
                print("Sub-test 3.3, animate partial updates" +
                      " w/ Python array buffering.")
            # . 3.4 - Big batch draw, with transforms indexed by IDs added.
            #   (Second FPS number with debug colors in the vertex shader off.)
            #   - 90,000 (300x300) spheres, TEXTURE_XFORMS = True, 26(29) FPS
            #   - 90,000 (300x300) spheres, N_CONST_XFORMS = 250, 26(29) FPS
            #   - 90,000 (300x300) spheres, N_CONST_XFORMS = 275, 0.3(0.6) FPS
            #     (What happens after 250?  CPU usage goes from 40% to 94%.)
            #   -160,000 (400x400) spheres, TEXTURE_XFORMS = True, 26 FPS
            #   -250,000 (500x500) spheres, TEXTURE_XFORMS = True, 26 FPS
            elif testCase == 3.4:
                print("Sub-test 3.4, add transforms indexed by IDs.")
                from graphics.drawing.gl_shaders import TEXTURE_XFORMS
                from graphics.drawing.gl_shaders import N_CONST_XFORMS
                from graphics.drawing.gl_shaders import UNIFORM_XFORMS
                if TEXTURE_XFORMS:
                    print "Transforms in texture memory."
                elif UNIFORM_XFORMS:
                    print "%d transforms in uniform memory." % N_CONST_XFORMS
                    pass
                else:
                    print "transforms not supported, error is likely"
                doTransforms = True
                pass

            centers = []
            radius = .5
            radii = []
            colors = []
            if not doTransforms:
                transformIDs = None
            else:
                transformIDs = []
                transformChunkID = -1  # Allocate IDs sequentially from 0.
                # For this test, allow arbitrarily chunking the primitives.
                primCounter = transformChunkLength
                transforms = []  # Accumulate transforms as a list of lists.

                # Initialize transforms with an identity matrix.
                # Transforms here are lists (or Numpy arrays) of 16 numbers.
                identity = ([1.0] + 4 * [0.0]) * 3 + [1.0]
                pass
            for x in range(nSpheres):
                for y in range(nSpheres):
                    centers += [sphereLoc(x, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x + y) / (nSpheres + nSpheres
                                        )  # 0 to 1 fraction.
                    thisRad = radius * (.75 + t * .25)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]

                    # Transforms go into a texture memory image if needed.
                    # Per-primitive Transform IDs go into an attribute VBO.
                    if doTransforms:
                        primCounter = primCounter + 1
                        if primCounter >= transformChunkLength:
                            # Start a new chunk, allocating a transform matrix.
                            primCounter = 0
                            transformChunkID += 1
                            if 0:  # 1
                                # Debug hack: Label mat[0,0] with the chunk ID.
                                # Vertex shader debug code shows these in blue.
                                # If viewed as geometry, it will be a slight
                                # stretch of the array in the X direction.
                                transforms += [
                                    [1.0 + transformChunkID / 100.0] +
                                    identity[1:]
                                ]
                            elif 0:  # 1
                                # Debug hack: Fill mat with mat.element pattern.
                                transforms += [[
                                    transformChunkID + i / 100.0
                                    for i in range(16)
                                ]]
                            else:
                                transforms += [identity]
                                pass
                            pass
                        # All of the primitives in a chunk have the same ID.
                        transformIDs += [transformChunkID]
                        pass

                    continue
                continue
            test_spheres = GLSphereBuffer()
            test_spheres.addSpheres(centers, radii, colors, transformIDs, None)
            if doTransforms:
                print("%d primitives in %d transform chunks of size <= %d" %
                      (nSpheres * nSpheres, len(transforms),
                       transformChunkLength))
                shader = drawing_globals.test_sphereShader
                shader.setupTransforms(transforms)
            pass
        else:
            shader = drawing_globals.test_sphereShader
            shader.configShader(glpane)

            # Update portions for animation.
            pulse = time.time()
            pulse -= floor(pulse)  # 0 to 1 in each second

            # Test animating updates on 80% of the radii in 45% of the columns.

            # . 3.1 - Update radii Python array per-column, send to graphics RAM.
            #   -  2,500 (50x50)   spheres 55 FPS
            #   - 10,000 (100x100) spheres 35 FPS
            #   - 17,424 (132x132) spheres 22.2 FPS
            #   - 40,000 (200x200) spheres 12.4 FPS
            #   - 90,000 (300x300) spheres  6.0 FPS
            if testCase == 3.1:
                # Not buffered, send each column change.
                radius = .5
                margin = nSpheres / 10
                for x in range(margin, nSpheres, 2):
                    radii = []
                    for y in range(margin, nSpheres - margin):
                        t = float(x + y) / (nSpheres + nSpheres
                                            )  # 0 to 1 fraction.
                        # Sphere radii progress from 3/4 to full size.
                        thisRad = radius * (.75 + t * .25)
                        phase = pulse + float(x + y) / nSpheres
                        radii += 8 * [thisRad - .1 + .1 * sin(phase * 2 * pi)]
                        continue
                    C_radii = numpy.array(radii, dtype=numpy.float32)
                    offset = x * nSpheres + margin
                    test_spheres.radii_vbo.update(offset * 8, C_radii)
                    continue
                pass

            # . 3.2 - Numpy buffered in C array, subscript assignments to C.
            #   -  2,500 (50x50)   spheres 48 FPS
            #   - 10,000 (100x100) spheres 17.4 FPS
            #   - 17,424 (132x132) spheres 11.2 FPS
            #   - 40,000 (200x200) spheres  5.5 FPS
            #   - 90,000 (300x300) spheres  2.5 FPS
            elif testCase == 3.2:
                # Buffered per-chunk at the C array level.
                radius = .5
                margin = nSpheres / 10
                global C_array
                if C_array is None:
                    # Replicate.
                    C_array = numpy.zeros((8 * (nSpheres - (2 * margin)), ),
                                          dtype=numpy.float32)
                    pass
                for x in range(margin, nSpheres, 2):
                    count = 0
                    for y in range(margin, nSpheres - margin):
                        t = float(x + y) / (nSpheres + nSpheres
                                            )  # 0 to 1 fraction.
                        # Sphere radii progress from 3/4 to full size.
                        thisRad = radius * (.75 + t * .25)
                        phase = pulse + float(x + y) / nSpheres
                        C_array[count*8:(count+1)*8] = \
                            thisRad-.1 + .1*sin(phase * 2*pi)
                        count += 1
                        continue
                    offset = x * nSpheres + margin
                    test_spheres.radii_vbo.update(offset * 8, C_array)
                    continue
                pass

            # . 3.3 - updateRadii in Python array, copy via C to graphics RAM.
            #   -  2,500 (50x50)   spheres 57 FPS
            #   - 10,000 (100x100) spheres 32 FPS
            #   - 17,424 (132x132) spheres 20 FPS
            #   - 40,000 (200x200) spheres 10.6 FPS
            #   - 90,000 (300x300) spheres  4.9 FPS
            elif testCase == 3.3:
                # Buffered at the Python level, batch the whole-array update.
                radius = .5
                margin = nSpheres / 10
                for x in range(margin, nSpheres, 2):
                    radii = []
                    for y in range(margin, nSpheres - margin):
                        t = float(x + y) / (nSpheres + nSpheres
                                            )  # 0 to 1 fraction.
                        # Sphere radii progress from 3/4 to full size.
                        thisRad = radius * (.75 + t * .25)
                        phase = pulse + float(x + y) / nSpheres
                        radii += [thisRad - .1 + .1 * sin(phase * 2 * pi)]
                        continue

                    test_spheres.updateRadii(  # Update, but don't send yet.
                        x * nSpheres + margin,
                        radii,
                        send=False)
                    continue
                test_spheres.sendRadii()
                pass

            # Options: color = [0.0, 1.0, 0.0], transform_id = 1, radius = 1.0
            test_spheres.draw()
        pass

    # NE1 with test toploop, separate sphere VBO/IBO box/shader draws (test case 4)
    # . 17,424 spheres (132x132 box/shader draw quads calls) 0.7 FPS
    elif testCase == 4:
        if test_ibo is None:
            print("Test case 4, %d^2 spheres\n  %s." %
                  (nSpheres,
                   "Separate VBO/IBO shader/box buffer sphere calls, no DL"))

            # Collect transformed bounding box vertices and offset indices.
            # Start at the lower-left corner, offset so the whole pattern comes
            # up centered on the origin.
            cubeVerts = drawing_globals.shaderCubeVerts
            cubeIndices = drawing_globals.shaderCubeIndices

            C_indices = numpy.array(cubeIndices, dtype=numpy.uint32)
            test_ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices,
                                      GL_STATIC_DRAW)
            test_ibo.unbind()

            C_verts = numpy.array(cubeVerts, dtype=numpy.float32)
            test_vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, C_verts,
                                      GL_STATIC_DRAW)
            test_vbo.unbind()
            pass
        else:
            drawing_globals.test_sphereShader.configShader(glpane)

            glEnableClientState(GL_VERTEX_ARRAY)

            test_vbo.bind()  # Vertex data comes from the vbo.
            glVertexPointer(3, GL_FLOAT, 0, None)

            drawing_globals.test_sphereShader.setActive(True)
            glDisable(GL_CULL_FACE)

            glColor3i(127, 127, 127)
            test_ibo.bind()  # Index data comes from the ibo.
            for x in range(nSpheres):
                for y in range(nSpheres):
                    # From drawsphere_worker_loop().
                    pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \
                          (y+y/10+y/100) * V(0, 1, 0)
                    radius = .5

                    glPushMatrix()
                    glTranslatef(pos[0], pos[1], pos[2])
                    glScale(radius, radius, radius)

                    glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None)

                    glPopMatrix()
                    continue
                continue

            drawing_globals.test_sphereShader.setActive(False)
            glEnable(GL_CULL_FACE)

            test_ibo.unbind()
            test_vbo.unbind()
            glDisableClientState(GL_VERTEX_ARRAY)
        pass

    # NE1 with test toploop,
    # One DL around separate VBO/IBO shader/box buffer sphere calls (test case 5)
    # . 17,424 spheres (1 box/shader DL draw call) 9.2 FPS
    elif testCase == 5:
        if test_dl is None:
            print("Test case 5, %d^2 spheres\n  %s." % (
                nSpheres,
                "One DL around separate VBO/IBO shader/box buffer sphere calls"
            ))

            # Collect transformed bounding box vertices and offset indices.
            # Start at the lower-left corner, offset so the whole pattern comes
            # up centered on the origin.
            cubeVerts = drawing_globals.shaderCubeVerts
            cubeIndices = drawing_globals.shaderCubeIndices

            C_indices = numpy.array(cubeIndices, dtype=numpy.uint32)
            test_ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices,
                                      GL_STATIC_DRAW)
            test_ibo.unbind()

            C_verts = numpy.array(cubeVerts, dtype=numpy.float32)
            test_vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, C_verts,
                                      GL_STATIC_DRAW)
            test_vbo.unbind()

            # Wrap a display list around the draws.
            test_dl = glGenLists(1)
            glNewList(test_dl, GL_COMPILE_AND_EXECUTE)

            glEnableClientState(GL_VERTEX_ARRAY)

            test_vbo.bind()  # Vertex data comes from the vbo.
            glVertexPointer(3, GL_FLOAT, 0, None)

            drawing_globals.test_sphereShader.setActive(True)
            glDisable(GL_CULL_FACE)

            glColor3i(127, 127, 127)
            test_ibo.bind()  # Index data comes from the ibo.
            for x in range(nSpheres):
                for y in range(nSpheres):
                    # From drawsphere_worker_loop().
                    pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \
                          (y+y/10+y/100) * V(0, 1, 0)
                    radius = .5

                    glPushMatrix()
                    glTranslatef(pos[0], pos[1], pos[2])
                    glScale(radius, radius, radius)

                    glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None)

                    glPopMatrix()
                    continue
                continue

            drawing_globals.test_sphereShader.setActive(False)
            glEnable(GL_CULL_FACE)

            test_ibo.unbind()
            test_vbo.unbind()
            glDisableClientState(GL_VERTEX_ARRAY)

            glEndList()
        else:
            glColor3i(127, 127, 127)
            glCallList(test_dl)
            pass
        pass

    # NE1 with test toploop,
    # N column DL's around VBO/IBO shader/box buffer sphere calls (test case 6)
    # .   2,500 (50x50)   spheres 58 FPS
    # .  10,000 (100x100) spheres 57 FPS
    # .  17,424 (132x132) spheres 56 FPS
    # .  40,000 (200x200) spheres 50 FPS
    # .  90,000 (300x300) spheres 28 FPS
    # . 160,000 (400x400) spheres 16.5 FPS
    # . 250,000 (500x500) spheres  3.2 FPS
    elif testCase == 6:
        if test_dls is None:
            print("Test case 6, %d^2 spheres\n  %s." %
                  (nSpheres,
                   "N col DL's around VBO/IBO shader/box buffer sphere calls"))

            # Wrap n display lists around the draws (one per column.)
            test_dls = glGenLists(
                nSpheres)  # Returns ID of first DL in the set.
            test_spheres = []
            for x in range(nSpheres):
                centers = []
                radius = .5
                radii = []
                colors = []
                # Each column is relative to its bottom sphere location.  Start
                # at the lower-left corner, offset so the whole pattern comes up
                # centered on the origin.
                start_pos = V(0, 0, 0)  # So it doesn't get subtracted twice.
                pos = sphereLoc(x, 0) - V(nSpheres / 2.0, nSpheres / 2.0, 0)
                for y in range(nSpheres):
                    centers += [sphereLoc(0, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x + y) / (nSpheres + nSpheres
                                        )  # 0 to 1 fraction.
                    thisRad = radius * (.75 + t * .25)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]
                    continue
                test_sphere = GLSphereBuffer()
                test_sphere.addSpheres(centers, radii, colors, None, None)
                test_spheres += [test_sphere]

                glNewList(test_dls + x, GL_COMPILE_AND_EXECUTE)
                glPushMatrix()
                glTranslatef(pos[0], pos[1], pos[2])

                test_sphere.draw()

                glPopMatrix()
                glEndList()
                continue
            pass
        else:
            shader = drawing_globals.test_sphereShader
            shader.configShader(glpane)  # Turn the lights on.
            for x in range(nSpheres):
                glCallList(test_dls + x)
                continue
            pass
        pass

    # NE1 with test toploop,
    # N column VBO sets of shader/box buffer sphere calls (test case 7)
    # .   2,500 (50x50)   spheres 50 FPS
    # .  10,000 (100x100) spheres 30.5 FPS
    # .  17,424 (132x132) spheres 23.5 FPS
    # .  40,000 (200x200) spheres 16.8 FPS
    # .  90,000 (300x300) spheres 10.8 FPS
    # . 160,000 (400x400) spheres  9.1 FPS
    # . 250,000 (500x500) spheres  7.3 FPS
    elif testCase == 7:
        if test_spheres is None:
            print("Test case 7, %d^2 spheres\n  %s." %
                  (nSpheres, "Per-column VBO/IBO chunk buffers"))
            test_spheres = []
            for x in range(nSpheres):
                centers = []
                radius = .5
                radii = []
                colors = []
                for y in range(nSpheres):
                    centers += [sphereLoc(x, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x + y) / (nSpheres + nSpheres
                                        )  # 0 to 1 fraction.
                    thisRad = radius * (.75 + t * .25)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]
                    continue
                _spheres1 = GLSphereBuffer()
                _spheres1.addSpheres(centers, radii, colors, None, None)
                test_spheres += [_spheres1]
                continue
            pass
        else:
            shader = drawing_globals.test_sphereShader
            shader.configShader(glpane)
            for chunk in test_spheres:
                chunk.draw()
        pass

    # NE1 with test toploop,
    # Short chunk VBO sets of shader/box buffer sphere calls (test case 8)
    # .     625 (25x25)   spheres 30 FPS,     79 chunk buffers of length 8.
    # .   2,500 (50x50)   spheres 13.6 FPS,  313 chunk buffers of length 8.
    # .  10,000 (100x100) spheres  6.4 FPS,  704 chunk buffers of length 8.
    # .  10,000 (100x100) spheres  3.3 FPS, 1250 chunk buffers of length 8.
    # .  17,424 (132x132) spheres  2.1 FPS, 2178 chunk buffers of length 8.
    # .   2,500 (50x50)   spheres 33.5 FPS,  105 chunk buffers of length 24.
    # .  17,424 (132x132) spheres  5.5 FPS,  726 chunk buffers of length 24.
    #
    # Subcase 8.1: CSDLs in a DrawingSet.  (Initial pass-through version.)
    # .   2,500 (50x50)   spheres 36.5 FPS,  105 chunk buffers of length 24.
    # .   5,625 (75x75)   spheres 16.1 FPS,  235 chunk buffers of length 24.
    # .  10,000 (100x100) spheres  0.5 FPS?!, 414 chunk buffers of length 24.
    #      Has to be <= 250 chunks for constant memory transforms?
    # .  10,000 (100x100) spheres 11.8 FPS, 50 chunk buffers of length 200.
    #      After a minute of startup.
    # .  10,000 (100x100) spheres 9.3 FPS, 200 chunk buffers of length 50.
    #      After a few minutes of startup.
    # Subcase 8.2: CSDLs in a DrawingSet with transforms. (Pass-through.)
    # .  10,000 (100x100) spheres  11.5 FPS, 50 chunk buffers of length 200.
    #
    # Subcase 8.1: CSDLs in a DrawingSet.  (First HunkBuffer version.)
    # Measured with auto-rotate on, ignoring startup and occasional outliers.
    # As before, on a 2 core, 2.4 GHz Intel MacBook Pro with GeForce 8600M GT.
    # HUNK_SIZE = 10000
    # .   2,500 (50x50)   spheres 140-200 FPS, 105 chunks of length 24.
    # .   5,625 (75x75)   spheres 155-175 FPS, 235 chunks of length 24.
    # .  10,000 (100x100) spheres 134-145 FPS, 50 chunks of length 200.
    # .  10,000 (100x100) spheres 130-143 FPS, 200 chunks of length 50.
    # .  10,000 (100x100) spheres 131-140 FPS, 1,250 chunks of length 8.
    #      Chunks are gathered into hunk buffers, so no chunk size speed diff.
    # .  17,424 (132x132) spheres 134-140 FPS, 88 chunks of length 200.
    # .  17,424 (132x132) spheres 131-140 FPS, 2,178 chunks of length 8.
    # HUNK_SIZE = 20000
    # .  17,424 (132x132) spheres 131-140 FPS, 88 chunks of length 200.
    # .  17,424 (132x132) spheres 130-141 FPS, 2,178 chunks of length 8.
    # HUNK_SIZE = 10000
    # .  40,000 (200x200) spheres 77.5-82.8 FPS, 5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 34.9-42.6 FPS, 11,2500 chunks of length 8.
    #      Spheres are getting down to pixel size, causing moire patterns.
    #      Rotate the sphere-array off-axis 45 degrees to minimize.
    #      (Try adding multi-sampled anti-aliasing, to the drawing test...)
    # . 160,000 (400x400) spheres 26.4-27.1 FPS, 20,000 chunks of length 8.
    # . 250,000 (500x500) spheres 16.8-17.1 FPS, 31,250 chunks of length 8.
    #      The pattern is getting too large, far-clipping is setting in.
    # . 360,000 (600x600) spheres 11.6-11.8 FPS, 45,000 chunks of length 8.
    #      Extreme far-clipping in the drawing test pattern.
    # HUNK_SIZE = 20000; no significant speed-up.
    # .  40,000 (200x200) spheres 75.9-81.5 FPS,  5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 41.2-42.4 FPS, 11,250 chunks of length 8.
    #      Spheres are getting down to pixel size, causing moire patterns.
    # . 160,000 (400x400) spheres 26.5-26.9 FPS, 20,000 chunks of length 8.
    # . 250,000 (500x500) spheres 16.5-17.1 FPS, 31,250 chunks of length 8.
    # . 360,000 (600x600) spheres 11.8-12.1 FPS, 45,000 chunks of length 8.
    # HUNK_SIZE = 5000; no significant slowdown or CPU load difference.
    # .  40,000 (200x200) spheres 81.0-83.8 FPS,  5,000 chunks of length 8.
    # . 160,000 (400x400) spheres 27.3-29.4 FPS, 20,000 chunks of length 8.
    # . 360,000 (600x600) spheres 11.7-12.1 FPS, 45,000 chunks of length 8.
    #
    # Retest after updating MacOS to 10.5.5, with TestGraphics, HUNK_SIZE = 5000
    # .  40,000 (200x200) spheres 68.7-74.4 FPS,  5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 39.4-42.0 FPS, 11,250 chunks of length 8.
    # . 160,000 (400x400) spheres 24.4-25.2 FPS, 20,000 chunks of length 8.
    # Retest with glMultiDrawElements drawing indexes in use, HUNK_SIZE = 5000
    # .  40,000 (200x200) spheres 52.8-54.4 FPS,  5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 22.8-23.3 FPS, 11,250 chunks of length 8.
    # . 160,000 (400x400) spheres 13.5-15.2 FPS, 20,000 chunks of length 8.
    #
    # Retest with reworked halo/sphere shader, HUNK_SIZE = 5000     [setup time]
    # .  17,424 (132x132) spheres 52.8-53.7 FPS,  2,178 chunks of length 8. [60]
    # .  40,000 (200x200) spheres 29.3-30.4 FPS,  5,000 chunks of length 8.[156]
    # .  90,000 (300x300) spheres 18.2-19.2 FPS, 11,250 chunks of length 8.[381]
    # . 160,000 (400x400) spheres 10.2-11.6 FPS, 20,000 chunks of length 8.[747]
    # Billboard drawing patterns instead of cubes, HUNK_SIZE = 5000 [setup time]
    # .  17,424 (132x132) spheres 49.7-55.7 FPS,  2,178 chunks of length 8. [35]
    # .  40,000 (200x200) spheres 39.6-40.8 FPS,  5,000 chunks of length 8. [88]
    # .  90,000 (300x300) spheres 18.9-19.5 FPS, 11,250 chunks of length 8.[225]
    # . 160,000 (400x400) spheres 11.2-11.7 FPS, 20,000 chunks of length 8.[476]
    #
    elif int(testCase) == 8:
        doTransforms = False
        doCylinders = False
        if test_spheres is None:
            # Setup.
            print("Test case 8, %d^2 primitives\n  %s, length %d." %
                  (nSpheres, "Short VBO/IBO chunk buffers", chunkLength))
            if testCase == 8.1:
                print(
                    "Sub-test 8.1, sphere chunks are in CSDL's in a DrawingSet."
                )
                test_DrawingSet = DrawingSet()
            elif testCase == 8.2:
                print("Sub-test 8.2, spheres, rotate with TransformControls.")
                test_DrawingSet = DrawingSet()
                doTransforms = True
            elif testCase == 8.3:
                print(
                    "Sub-test 8.3, cylinder chunks are in CSDL's in a DrawingSet."
                )
                test_DrawingSet = DrawingSet()
                doCylinders = True
                pass
            if test_DrawingSet:
                # note: doesn't happen in test 8.0, which causes a bug then. [bruce 090223 comment]
                print "constructed test_DrawingSet =", test_DrawingSet

            if USE_GRAPHICSMODE_DRAW:
                print("Use graphicsMode.Draw_model for DrawingSet in paintGL.")
                pass

            t1 = time.time()

            if doTransforms:
                # Provide several TransformControls to test separate action.
                global numTCs, TCs
                numTCs = 3
                TCs = [TransformControl() for i in range(numTCs)]
                pass

            def primCSDL(centers, radii, colors):
                if not doTransforms:
                    csdl = ColorSortedDisplayList()  # Transformless.
                else:
                    # Test pattern for TransformControl usage - vertical columns
                    # of TC domains, separated by X coord of first center point.
                    # Chunking will be visible when transforms are changed.
                    xCoord = centers[0][0] - start_pos[
                        0]  # Negate centering X.
                    xPercent = (
                        xCoord /
                        (nSpheres + nSpheres / 10 + nSpheres / 100 - 1 +
                         (nSpheres <= 1)))
                    xTenth = int(xPercent * 10 + .5)
                    csdl = ColorSortedDisplayList(TCs[xTenth % numTCs])
                    pass

                # Test selection using the CSDL glname.
                ColorSorter.pushName(csdl.glname)
                ColorSorter.start(glpane, csdl)
                for (color, center, radius) in zip(colors, centers, radii):
                    if not doCylinders:
                        # Through ColorSorter to the sphere primitive buffer...
                        drawsphere(color, center, radius,
                                   DRAWSPHERE_DETAIL_LEVEL)
                    else:
                        # Through ColorSorter to cylinder primitive buffer...
                        if not drawing_globals.cylinderShader_available():
                            print "warning: not cylinderShader_available(), error is likely:"
                        if (True and  # Whether to do tapered shader-cylinders.
                                # Display List cylinders don't support taper.
                                glpane.glprefs.cylinderShader_desired()):
                            ###cylRad = (radius/2.0, (.75-radius)/2.0)
                            cylRad = (radius / 1.5 - .167, .3 - radius / 1.5)
                        else:
                            cylRad = radius / 2.0
                            pass
                        endPt2 = center + V(0.5, 0.0, 0.0)  # 0.5, -0.5)
                        drawcylinder(color, center, endPt2, cylRad)
                        global test_endpoints
                        test_endpoints += [(center, endPt2)]
                        pass
                    continue
                ColorSorter.popName()
                ColorSorter.finish(draw_now=True)

                test_DrawingSet.addCSDL(csdl)
                return csdl

            if testCase == 8:
                #bruce 090223 revised to try to avoid traceback
                def chunkFn(centers, radii, colors):
                    res = GLSphereBuffer()
                    res.addSpheres(centers, radii, colors, None, None)
                    return res

                pass
            else:
                chunkFn = primCSDL
                pass

            test_spheres = []
            radius = .5
            centers = []
            radii = []
            colors = []
            global test_endpoints
            test_endpoints = []

            for x in range(nSpheres):
                for y in range(nSpheres):
                    centers += [sphereLoc(x, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x + y) / (nSpheres + nSpheres
                                        )  # 0 to 1 fraction.
                    thisRad = radius * (.5 + t * .5)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]

                    # Put out short chunk buffers.
                    if len(centers) >= chunkLength:
                        test_spheres += [chunkFn(centers, radii, colors)]
                        centers = []
                        radii = []
                        colors = []
                    continue
                continue
            # Remainder fraction buffer.
            if len(centers):
                test_spheres += [chunkFn(centers, radii, colors)]
                pass
            print "Setup time", time.time() - t1, "seconds."
            print "%d chunk buffers" % len(test_spheres)
            pass
        elif not initOnly:  # Run.
            test_Draw_8x(glpane)
        pass
    elif testCase == 100:  #bruce 090102
        # before making more of these, modularize it somehow
        from commands.TestGraphics.test_selection_redraw import test_selection_redraw
        test_class = test_selection_redraw
        params = (nSpheres, )
        # note: test size is not directly comparable to other tests with same value of nSpheres
        if test_Object is None \
           or not isinstance(test_Object, test_class) \
           or test_Object.current_params() != params: # review: same_vals?
            # Setup.
            if test_Object:
                test_Object.destroy()
            test_Object = test_class(*params)
            test_Object.activate()
            print test_Object
            pass
        # review: safe to change elif to if? not sure, GL state is only initialized below
        elif not initOnly:  # Run.
            test_Object.draw_complete()
            pass
        pass

    if not initOnly:
        glMatrixMode(GL_MODELVIEW)
        glFlush()
        pass

    first_time = False
    return
예제 #18
0
    def _bondDraw(self, color, p0, p1, carbonAt):
        if self.dispMode == 'Tubes':
            drawcylinder(color, p0, p1, 0.2)
        else:
            if carbonAt < 0:
                drawsphere(color, p0, 0.5, 1)
                drawsphere(color, p1, 0.5, 1)
            elif carbonAt == 0:
                drawsphere(color, p0, 0.5, 1)
                drawsphere(color, p1, 0.2, 1)
            elif carbonAt == 1:
                drawsphere(color, p0, 0.2, 1)
                drawsphere(color, p1, 0.5, 1)

            drawline(white, p0, p1)  
예제 #19
0
파일: Rect.py 프로젝트: elfion/nanoengineer
 def draw(self):
     drawsphere(self.fix_color(self.color), self.center, self.radius, self.detailLevel)
    def _drawDnaRubberbandLine(self):
        """
        Overrides superclass method. It loops through the segments being resized
        and draws the rubberband lines for all. NOT this could be SLOW
        @see: MultipleDnaSegmentResize_EditCommand.getDnaRibbonParams() for
              comments.
        @TODO: needs more cleanup
        """

        handleType = ''
        if self.command.grabbedHandle is not None:
            if self.command.grabbedHandle in [
                    self.command.rotationHandle1, self.command.rotationHandle2
            ]:
                handleType = 'ROTATION_HANDLE'
            else:
                handleType = 'RESIZE_HANDLE'

        if handleType and handleType == 'RESIZE_HANDLE':

            # textColor is not used. I'm going to ask Ninad if this should
            # stay in or should be removed. --Mark
            #textColor = env.prefs[cursorTextColor_prefs_key] # Mark 2008-08-28

            for segment in self.command.getResizeSegmentList():
                self.command.currentStruct = segment
                params_when_adding_bases, params_when_removing_bases = \
                                        self.command.getDnaRibbonParams()

                if params_when_adding_bases:
                    end1, \
                        end2, \
                        basesPerTurn,\
                        duplexRise, \
                        ribbon1_start_point, \
                        ribbon2_start_point, \
                        ribbon1_direction, \
                        ribbon2_direction, \
                        ribbon1Color, \
                        ribbon2Color = params_when_adding_bases

                    #Note: The displayStyle argument for the rubberband line should
                    #really be obtained from self.command.struct. But the struct
                    #is a DnaSegment (a Group) and doesn't have attr 'display'
                    #Should we then obtain this information from one of its strandChunks?
                    #but what if two strand chunks and axis chunk are rendered
                    #in different display styles? since situation may vary, lets
                    #use self.glpane.displayMode for rubberbandline displayMode
                    drawDnaRibbons(
                        self.glpane,
                        end1,
                        end2,
                        basesPerTurn,
                        duplexRise,
                        self.glpane.scale,
                        self.glpane.lineOfSight,
                        self.glpane.displayMode,
                        ribbonThickness=4.0,
                        ribbon1_start_point=ribbon1_start_point,
                        ribbon2_start_point=ribbon2_start_point,
                        ribbon1_direction=ribbon1_direction,
                        ribbon2_direction=ribbon2_direction,
                        ribbon1Color=ribbon1Color,
                        ribbon2Color=ribbon2Color,
                    )

                    #Draw a sphere that indicates the current position of
                    #the resize end of each segment .
                    drawsphere(env.prefs[selectionColor_prefs_key],
                               end2,
                               SPHERE_RADIUS_2,
                               SPHERE_DRAWLEVEL,
                               opacity=SPHERE_OPACITY)

                    #Draw the text next to the cursor that gives info about
                    #number of base pairs etc
                    self._drawCursorText(position=end2)

                elif params_when_removing_bases:
                    end2 = params_when_removing_bases
                    #Draw a sphere that indicates the current position of
                    #the resize end of each segment.
                    drawsphere(darkred,
                               end2,
                               SPHERE_RADIUS_2,
                               SPHERE_DRAWLEVEL,
                               opacity=SPHERE_OPACITY)

                    #Draw the text next to the cursor that gives info about
                    #number of base pairs etc
                    self._drawCursorText(position=end2)

                #Reset the command.currentStruct to None. (it is set to 'segment'
                #at the beginning of the for loop.
                self.command.currentStruct = None
예제 #21
0
def test_drawing(glpane, initOnly = False):
    """
    When TEST_DRAWING is enabled at the start of
    graphics/widgets/GLPane_rendering_methods.py,
    and when TestGraphics_Command is run (see its documentation
    for various ways to do that),
    this file is loaded and GLPane.paintGL() calls the
    test_drawing() function instead of the usual body of paintGL().
    """
    # WARNING: this duplicates some code with test_Draw_model().

    # Load the sphere shaders if needed.
    global _USE_SHADERS
    if _USE_SHADERS:
        if not drawing_globals.test_sphereShader:
            print "test_drawing: Loading sphere shaders."

            try:
                from graphics.drawing.gl_shaders import GLSphereShaderObject
                drawing_globals.test_sphereShader = GLSphereShaderObject()
                ##### REVIEW: is this compatible with my refactoring in drawing_globals?
                # If not, use of Test Graphics Performance command might cause subsequent
                # bugs in other code. Ideally we'd call the new methods that encapsulate
                # this, to setup shaders. [bruce 090304 comment]

                print "test_drawing: Sphere-shader initialization is complete.\n"
            except:
                _USE_SHADERS = False
                print "test_drawing: Exception while loading sphere shaders, will reraise and not try again"
                raise
            pass

    global start_pos, first_time

    if first_time:
        # Set up the viewing scale, but then let interactive zooming work.
        glpane.scale = nSpheres * .6
        pass

    # This same function gets called to set up for drawing, and to draw.
    if not initOnly:
        glpane._setup_modelview()
        glpane._setup_projection()
        ##glpane._compute_frustum_planes()

        glClearColor(64.0, 64.0, 64.0, 1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT )
        ##glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )

        glMatrixMode(GL_MODELVIEW)
        pass

    global test_csdl, test_dl, test_dls, test_ibo, test_vbo, test_spheres
    global test_DrawingSet, test_endpoints, test_Object

    # See below for test case descriptions and timings on a MacBook Pro.
    # The Qt event toploop in NE1 tops out at about 60 frames-per-second.

    # NE1 with test toploop, single CSDL per draw (test case 1)
    # . 17,424 spheres (132x132, through the color sorter) 4.8 FPS
    #   Russ 080919: More recently, 12.2 FPS.
    # . Level 2 spheres have 9 triangles x 20 faces, 162 distinct vertices,
    #   visited on the average 2.3 times, giving 384 tri-strip vertices.
    # . 17,424 spheres is 6.7 million tri-strip vertices.  (6,690,816)
    if testCase == 1:
        if test_csdl is None:
            print ("Test case 1, %d^2 spheres\n  %s." %
                   (nSpheres, "ColorSorter"))

            test_csdl = ColorSortedDisplayList()
            ColorSorter.start(None, test_csdl)
            drawsphere([0.5, 0.5, 0.5], # color
                       [0.0, 0.0, 0.0], # pos
                       .5, # radius
                       DRAWSPHERE_DETAIL_LEVEL,
                       testloop = nSpheres )
            ColorSorter.finish(draw_now = True)
            pass
        else:
            test_csdl.draw()
        pass

    # NE1 with test toploop, single display list per draw (test case 2)
    # . 10,000 spheres (all drawing modes) 17.5 FPS
    # . 17,424 spheres (132x132, manual display list) 11.1 FPS
    # . 40,000 spheres (mode 5 - VBO/IBO spheres from DL's) 2.2 FPS
    # . 40,000 spheres (mode 6 - Sphere shaders from DL's) 2.5 FPS
    # . 90,000 spheres (all drawing modes) 1.1 FPS
    elif testCase == 2:
        if test_dl is None:
            print ("Test case 2, %d^2 spheres\n  %s." %
                   (nSpheres, "One display list calling primitive dl's"))

            test_dl = glGenLists(1)
            glNewList(test_dl, GL_COMPILE_AND_EXECUTE)
            drawsphere_worker_loop(([0.0, 0.0, 0.0], # pos
                                    .5, # radius
                                    DRAWSPHERE_DETAIL_LEVEL,
                                    nSpheres ))
            glEndList()
            pass
        else:
            glColor3i(127, 127, 127)
            glCallList(test_dl)
        pass

    # NE1 with test toploop, one big chunk VBO/IBO of box quads (test case 3)
    # .  17,424 spheres (1 box/shader draw call) 43.7 FPS
    # .  17,424 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 57.7 FPS
    # .  40,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 56.7 FPS
    # .  90,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 52.7 FPS
    # . 160,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 41.4 FPS
    # . 250,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 27.0 FPS
    elif int(testCase) == 3:
        doTransforms = False
        if test_spheres is None:
            print ("Test case 3, %d^2 spheres\n  %s." %
                   (nSpheres, "One big VBO/IBO chunk buffer"))
            if testCase == 3.1:
                print ("Sub-test 3.1, animate partial updates.")
            elif testCase == 3.2:
                print ("Sub-test 3.2, animate partial updates" +
                       " w/ C per-chunk array buffering.")
            elif testCase == 3.3:
                print ("Sub-test 3.3, animate partial updates" +
                       " w/ Python array buffering.")
            # . 3.4 - Big batch draw, with transforms indexed by IDs added.
            #   (Second FPS number with debug colors in the vertex shader off.)
            #   - 90,000 (300x300) spheres, TEXTURE_XFORMS = True, 26(29) FPS
            #   - 90,000 (300x300) spheres, N_CONST_XFORMS = 250, 26(29) FPS
            #   - 90,000 (300x300) spheres, N_CONST_XFORMS = 275, 0.3(0.6) FPS
            #     (What happens after 250?  CPU usage goes from 40% to 94%.)
            #   -160,000 (400x400) spheres, TEXTURE_XFORMS = True, 26 FPS
            #   -250,000 (500x500) spheres, TEXTURE_XFORMS = True, 26 FPS
            elif testCase == 3.4:
                print ("Sub-test 3.4, add transforms indexed by IDs.")
                from graphics.drawing.gl_shaders import TEXTURE_XFORMS
                from graphics.drawing.gl_shaders import N_CONST_XFORMS
                from graphics.drawing.gl_shaders import UNIFORM_XFORMS
                if TEXTURE_XFORMS:
                    print "Transforms in texture memory."
                elif UNIFORM_XFORMS:
                    print "%d transforms in uniform memory." % N_CONST_XFORMS
                    pass
                else:
                    print "transforms not supported, error is likely"
                doTransforms = True
                pass

            centers = []
            radius = .5
            radii = []
            colors = []
            if not doTransforms:
                transformIDs = None
            else:
                transformIDs = []
                transformChunkID = -1   # Allocate IDs sequentially from 0.
                # For this test, allow arbitrarily chunking the primitives.
                primCounter = transformChunkLength
                transforms = []      # Accumulate transforms as a list of lists.

                # Initialize transforms with an identity matrix.
                # Transforms here are lists (or Numpy arrays) of 16 numbers.
                identity = ([1.0] + 4*[0.0]) * 3 + [1.0]
                pass
            for x in range(nSpheres):
                for y in range(nSpheres):
                    centers += [sphereLoc(x, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                    thisRad = radius * (.75 + t*.25)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]

                    # Transforms go into a texture memory image if needed.
                    # Per-primitive Transform IDs go into an attribute VBO.
                    if doTransforms:
                        primCounter = primCounter + 1
                        if primCounter >= transformChunkLength:
                            # Start a new chunk, allocating a transform matrix.
                            primCounter = 0
                            transformChunkID += 1
                            if 0: # 1
                                # Debug hack: Label mat[0,0] with the chunk ID.
                                # Vertex shader debug code shows these in blue.
                                # If viewed as geometry, it will be a slight
                                # stretch of the array in the X direction.
                                transforms += [
                                    [1.0+transformChunkID/100.0] + identity[1:]]
                            elif 0: # 1
                                # Debug hack: Fill mat with mat.element pattern.
                                transforms += [
                                    [transformChunkID +
                                     i/100.0 for i in range(16)]]
                            else:
                                transforms += [identity]
                                pass
                            pass
                        # All of the primitives in a chunk have the same ID.
                        transformIDs += [transformChunkID]
                        pass

                    continue
                continue
            test_spheres = GLSphereBuffer()
            test_spheres.addSpheres(centers, radii, colors, transformIDs, None)
            if doTransforms:
                print ("%d primitives in %d transform chunks of size <= %d" %
                       (nSpheres * nSpheres, len(transforms),
                        transformChunkLength))
                shader = drawing_globals.test_sphereShader
                shader.setupTransforms(transforms)
            pass
        else:
            shader = drawing_globals.test_sphereShader
            shader.configShader(glpane)

            # Update portions for animation.
            pulse = time.time()
            pulse -= floor(pulse) # 0 to 1 in each second

            # Test animating updates on 80% of the radii in 45% of the columns.

            # . 3.1 - Update radii Python array per-column, send to graphics RAM.
            #   -  2,500 (50x50)   spheres 55 FPS
            #   - 10,000 (100x100) spheres 35 FPS
            #   - 17,424 (132x132) spheres 22.2 FPS
            #   - 40,000 (200x200) spheres 12.4 FPS
            #   - 90,000 (300x300) spheres  6.0 FPS
            if testCase == 3.1:
                # Not buffered, send each column change.
                radius = .5
                margin = nSpheres/10
                for x in range(margin, nSpheres, 2):
                    radii = []
                    for y in range(margin, nSpheres-margin):
                        t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                        # Sphere radii progress from 3/4 to full size.
                        thisRad = radius * (.75 + t*.25)
                        phase = pulse + float(x+y)/nSpheres
                        radii += 8 * [thisRad-.1 + .1*sin(phase * 2*pi)]
                        continue
                    C_radii = numpy.array(radii, dtype=numpy.float32)
                    offset = x*nSpheres + margin
                    test_spheres.radii_vbo.update(offset * 8, C_radii)
                    continue
                pass

            # . 3.2 - Numpy buffered in C array, subscript assignments to C.
            #   -  2,500 (50x50)   spheres 48 FPS
            #   - 10,000 (100x100) spheres 17.4 FPS
            #   - 17,424 (132x132) spheres 11.2 FPS
            #   - 40,000 (200x200) spheres  5.5 FPS
            #   - 90,000 (300x300) spheres  2.5 FPS
            elif testCase == 3.2:
                # Buffered per-chunk at the C array level.
                radius = .5
                margin = nSpheres/10
                global C_array
                if C_array is None:
                    # Replicate.
                    C_array = numpy.zeros((8 * (nSpheres-(2*margin)),),
                                          dtype=numpy.float32)
                    pass
                for x in range(margin, nSpheres, 2):
                    count = 0
                    for y in range(margin, nSpheres-margin):
                        t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                        # Sphere radii progress from 3/4 to full size.
                        thisRad = radius * (.75 + t*.25)
                        phase = pulse + float(x+y)/nSpheres
                        C_array[count*8:(count+1)*8] = \
                            thisRad-.1 + .1*sin(phase * 2*pi)
                        count += 1
                        continue
                    offset = x*nSpheres + margin
                    test_spheres.radii_vbo.update(offset * 8, C_array)
                    continue
                pass

            # . 3.3 - updateRadii in Python array, copy via C to graphics RAM.
            #   -  2,500 (50x50)   spheres 57 FPS
            #   - 10,000 (100x100) spheres 32 FPS
            #   - 17,424 (132x132) spheres 20 FPS
            #   - 40,000 (200x200) spheres 10.6 FPS
            #   - 90,000 (300x300) spheres  4.9 FPS
            elif testCase == 3.3:
                # Buffered at the Python level, batch the whole-array update.
                radius = .5
                margin = nSpheres/10
                for x in range(margin, nSpheres, 2):
                    radii = []
                    for y in range(margin, nSpheres-margin):
                        t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                        # Sphere radii progress from 3/4 to full size.
                        thisRad = radius * (.75 + t*.25)
                        phase = pulse + float(x+y)/nSpheres
                        radii += [thisRad-.1 + .1*sin(phase * 2*pi)]
                        continue

                    test_spheres.updateRadii( # Update, but don't send yet.
                        x*nSpheres + margin, radii, send = False)
                    continue
                test_spheres.sendRadii()
                pass

            # Options: color = [0.0, 1.0, 0.0], transform_id = 1, radius = 1.0
            test_spheres.draw()
        pass

    # NE1 with test toploop, separate sphere VBO/IBO box/shader draws (test case 4)
    # . 17,424 spheres (132x132 box/shader draw quads calls) 0.7 FPS
    elif testCase == 4:
        if test_ibo is None:
            print ("Test case 4, %d^2 spheres\n  %s." %
                   (nSpheres,
                    "Separate VBO/IBO shader/box buffer sphere calls, no DL"))

            # Collect transformed bounding box vertices and offset indices.
            # Start at the lower-left corner, offset so the whole pattern comes
            # up centered on the origin.
            cubeVerts = drawing_globals.shaderCubeVerts
            cubeIndices = drawing_globals.shaderCubeIndices

            C_indices = numpy.array(cubeIndices, dtype=numpy.uint32)
            test_ibo = GLBufferObject(
                GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW)
            test_ibo.unbind()

            C_verts = numpy.array(cubeVerts, dtype=numpy.float32)
            test_vbo = GLBufferObject(
                GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW)
            test_vbo.unbind()
            pass
        else:
            drawing_globals.test_sphereShader.configShader(glpane)

            glEnableClientState(GL_VERTEX_ARRAY)

            test_vbo.bind()             # Vertex data comes from the vbo.
            glVertexPointer(3, GL_FLOAT, 0, None)

            drawing_globals.test_sphereShader.setActive(True)
            glDisable(GL_CULL_FACE)

            glColor3i(127, 127, 127)
            test_ibo.bind()             # Index data comes from the ibo.
            for x in range(nSpheres):
                for y in range(nSpheres):
                    # From drawsphere_worker_loop().
                    pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \
                          (y+y/10+y/100) * V(0, 1, 0)
                    radius = .5

                    glPushMatrix()
                    glTranslatef(pos[0], pos[1], pos[2])
                    glScale(radius,radius,radius)

                    glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None)

                    glPopMatrix()
                    continue
                continue

            drawing_globals.test_sphereShader.setActive(False)
            glEnable(GL_CULL_FACE)

            test_ibo.unbind()
            test_vbo.unbind()
            glDisableClientState(GL_VERTEX_ARRAY)
        pass

    # NE1 with test toploop,
    # One DL around separate VBO/IBO shader/box buffer sphere calls (test case 5)
    # . 17,424 spheres (1 box/shader DL draw call) 9.2 FPS
    elif testCase == 5:
        if test_dl is None:
            print ("Test case 5, %d^2 spheres\n  %s." %
                   (nSpheres,
                    "One DL around separate VBO/IBO shader/box buffer sphere calls"))

            # Collect transformed bounding box vertices and offset indices.
            # Start at the lower-left corner, offset so the whole pattern comes
            # up centered on the origin.
            cubeVerts = drawing_globals.shaderCubeVerts
            cubeIndices = drawing_globals.shaderCubeIndices

            C_indices = numpy.array(cubeIndices, dtype=numpy.uint32)
            test_ibo = GLBufferObject(
                GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW)
            test_ibo.unbind()

            C_verts = numpy.array(cubeVerts, dtype=numpy.float32)
            test_vbo = GLBufferObject(
                GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW)
            test_vbo.unbind()

            # Wrap a display list around the draws.
            test_dl = glGenLists(1)
            glNewList(test_dl, GL_COMPILE_AND_EXECUTE)

            glEnableClientState(GL_VERTEX_ARRAY)

            test_vbo.bind()             # Vertex data comes from the vbo.
            glVertexPointer(3, GL_FLOAT, 0, None)

            drawing_globals.test_sphereShader.setActive(True)
            glDisable(GL_CULL_FACE)

            glColor3i(127, 127, 127)
            test_ibo.bind()             # Index data comes from the ibo.
            for x in range(nSpheres):
                for y in range(nSpheres):
                    # From drawsphere_worker_loop().
                    pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \
                          (y+y/10+y/100) * V(0, 1, 0)
                    radius = .5

                    glPushMatrix()
                    glTranslatef(pos[0], pos[1], pos[2])
                    glScale(radius,radius,radius)

                    glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None)

                    glPopMatrix()
                    continue
                continue

            drawing_globals.test_sphereShader.setActive(False)
            glEnable(GL_CULL_FACE)

            test_ibo.unbind()
            test_vbo.unbind()
            glDisableClientState(GL_VERTEX_ARRAY)

            glEndList()
        else:
            glColor3i(127, 127, 127)
            glCallList(test_dl)
            pass
        pass

    # NE1 with test toploop,
    # N column DL's around VBO/IBO shader/box buffer sphere calls (test case 6)
    # .   2,500 (50x50)   spheres 58 FPS
    # .  10,000 (100x100) spheres 57 FPS
    # .  17,424 (132x132) spheres 56 FPS
    # .  40,000 (200x200) spheres 50 FPS
    # .  90,000 (300x300) spheres 28 FPS
    # . 160,000 (400x400) spheres 16.5 FPS
    # . 250,000 (500x500) spheres  3.2 FPS
    elif testCase == 6:
        if test_dls is None:
            print ("Test case 6, %d^2 spheres\n  %s." %
                   (nSpheres,
                    "N col DL's around VBO/IBO shader/box buffer sphere calls"))

            # Wrap n display lists around the draws (one per column.)
            test_dls = glGenLists(nSpheres) # Returns ID of first DL in the set.
            test_spheres = []
            for x in range(nSpheres):
                centers = []
                radius = .5
                radii = []
                colors = []
                # Each column is relative to its bottom sphere location.  Start
                # at the lower-left corner, offset so the whole pattern comes up
                # centered on the origin.
                start_pos = V(0, 0, 0)  # So it doesn't get subtracted twice.
                pos = sphereLoc(x, 0) - V(nSpheres/2.0, nSpheres/2.0, 0)
                for y in range(nSpheres):
                    centers += [sphereLoc(0, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                    thisRad = radius * (.75 + t*.25)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]
                    continue
                test_sphere = GLSphereBuffer()
                test_sphere.addSpheres(centers, radii, colors, None, None)
                test_spheres += [test_sphere]

                glNewList(test_dls + x, GL_COMPILE_AND_EXECUTE)
                glPushMatrix()
                glTranslatef(pos[0], pos[1], pos[2])

                test_sphere.draw()

                glPopMatrix()
                glEndList()
                continue
            pass
        else:
            shader = drawing_globals.test_sphereShader
            shader.configShader(glpane) # Turn the lights on.
            for x in range(nSpheres):
                glCallList(test_dls + x)
                continue
            pass
        pass

    # NE1 with test toploop,
    # N column VBO sets of shader/box buffer sphere calls (test case 7)
    # .   2,500 (50x50)   spheres 50 FPS
    # .  10,000 (100x100) spheres 30.5 FPS
    # .  17,424 (132x132) spheres 23.5 FPS
    # .  40,000 (200x200) spheres 16.8 FPS
    # .  90,000 (300x300) spheres 10.8 FPS
    # . 160,000 (400x400) spheres  9.1 FPS
    # . 250,000 (500x500) spheres  7.3 FPS
    elif testCase == 7:
        if test_spheres is None:
            print ("Test case 7, %d^2 spheres\n  %s." %
                   (nSpheres, "Per-column VBO/IBO chunk buffers"))
            test_spheres = []
            for x in range(nSpheres):
                centers = []
                radius = .5
                radii = []
                colors = []
                for y in range(nSpheres):
                    centers += [sphereLoc(x, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                    thisRad = radius * (.75 + t*.25)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]
                    continue
                _spheres1 = GLSphereBuffer()
                _spheres1.addSpheres(centers, radii, colors, None, None)
                test_spheres += [_spheres1]
                continue
            pass
        else:
            shader = drawing_globals.test_sphereShader
            shader.configShader(glpane)
            for chunk in test_spheres:
                chunk.draw()
        pass

    # NE1 with test toploop,
    # Short chunk VBO sets of shader/box buffer sphere calls (test case 8)
    # .     625 (25x25)   spheres 30 FPS,     79 chunk buffers of length 8.
    # .   2,500 (50x50)   spheres 13.6 FPS,  313 chunk buffers of length 8.
    # .  10,000 (100x100) spheres  6.4 FPS,  704 chunk buffers of length 8.
    # .  10,000 (100x100) spheres  3.3 FPS, 1250 chunk buffers of length 8.
    # .  17,424 (132x132) spheres  2.1 FPS, 2178 chunk buffers of length 8.
    # .   2,500 (50x50)   spheres 33.5 FPS,  105 chunk buffers of length 24.
    # .  17,424 (132x132) spheres  5.5 FPS,  726 chunk buffers of length 24.
    #
    # Subcase 8.1: CSDLs in a DrawingSet.  (Initial pass-through version.)
    # .   2,500 (50x50)   spheres 36.5 FPS,  105 chunk buffers of length 24.
    # .   5,625 (75x75)   spheres 16.1 FPS,  235 chunk buffers of length 24.
    # .  10,000 (100x100) spheres  0.5 FPS?!, 414 chunk buffers of length 24.
    #      Has to be <= 250 chunks for constant memory transforms?
    # .  10,000 (100x100) spheres 11.8 FPS, 50 chunk buffers of length 200.
    #      After a minute of startup.
    # .  10,000 (100x100) spheres 9.3 FPS, 200 chunk buffers of length 50.
    #      After a few minutes of startup.
    # Subcase 8.2: CSDLs in a DrawingSet with transforms. (Pass-through.)
    # .  10,000 (100x100) spheres  11.5 FPS, 50 chunk buffers of length 200.
    #
    # Subcase 8.1: CSDLs in a DrawingSet.  (First HunkBuffer version.)
    # Measured with auto-rotate on, ignoring startup and occasional outliers.
    # As before, on a 2 core, 2.4 GHz Intel MacBook Pro with GeForce 8600M GT.
    # HUNK_SIZE = 10000
    # .   2,500 (50x50)   spheres 140-200 FPS, 105 chunks of length 24.
    # .   5,625 (75x75)   spheres 155-175 FPS, 235 chunks of length 24.
    # .  10,000 (100x100) spheres 134-145 FPS, 50 chunks of length 200.
    # .  10,000 (100x100) spheres 130-143 FPS, 200 chunks of length 50.
    # .  10,000 (100x100) spheres 131-140 FPS, 1,250 chunks of length 8.
    #      Chunks are gathered into hunk buffers, so no chunk size speed diff.
    # .  17,424 (132x132) spheres 134-140 FPS, 88 chunks of length 200.
    # .  17,424 (132x132) spheres 131-140 FPS, 2,178 chunks of length 8.
    # HUNK_SIZE = 20000
    # .  17,424 (132x132) spheres 131-140 FPS, 88 chunks of length 200.
    # .  17,424 (132x132) spheres 130-141 FPS, 2,178 chunks of length 8.
    # HUNK_SIZE = 10000
    # .  40,000 (200x200) spheres 77.5-82.8 FPS, 5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 34.9-42.6 FPS, 11,2500 chunks of length 8.
    #      Spheres are getting down to pixel size, causing moire patterns.
    #      Rotate the sphere-array off-axis 45 degrees to minimize.
    #      (Try adding multi-sampled anti-aliasing, to the drawing test...)
    # . 160,000 (400x400) spheres 26.4-27.1 FPS, 20,000 chunks of length 8.
    # . 250,000 (500x500) spheres 16.8-17.1 FPS, 31,250 chunks of length 8.
    #      The pattern is getting too large, far-clipping is setting in.
    # . 360,000 (600x600) spheres 11.6-11.8 FPS, 45,000 chunks of length 8.
    #      Extreme far-clipping in the drawing test pattern.
    # HUNK_SIZE = 20000; no significant speed-up.
    # .  40,000 (200x200) spheres 75.9-81.5 FPS,  5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 41.2-42.4 FPS, 11,250 chunks of length 8.
    #      Spheres are getting down to pixel size, causing moire patterns.
    # . 160,000 (400x400) spheres 26.5-26.9 FPS, 20,000 chunks of length 8.
    # . 250,000 (500x500) spheres 16.5-17.1 FPS, 31,250 chunks of length 8.
    # . 360,000 (600x600) spheres 11.8-12.1 FPS, 45,000 chunks of length 8.
    # HUNK_SIZE = 5000; no significant slowdown or CPU load difference.
    # .  40,000 (200x200) spheres 81.0-83.8 FPS,  5,000 chunks of length 8.
    # . 160,000 (400x400) spheres 27.3-29.4 FPS, 20,000 chunks of length 8.
    # . 360,000 (600x600) spheres 11.7-12.1 FPS, 45,000 chunks of length 8.
    #
    # Retest after updating MacOS to 10.5.5, with TestGraphics, HUNK_SIZE = 5000
    # .  40,000 (200x200) spheres 68.7-74.4 FPS,  5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 39.4-42.0 FPS, 11,250 chunks of length 8.
    # . 160,000 (400x400) spheres 24.4-25.2 FPS, 20,000 chunks of length 8.
    # Retest with glMultiDrawElements drawing indexes in use, HUNK_SIZE = 5000
    # .  40,000 (200x200) spheres 52.8-54.4 FPS,  5,000 chunks of length 8.
    # .  90,000 (300x300) spheres 22.8-23.3 FPS, 11,250 chunks of length 8.
    # . 160,000 (400x400) spheres 13.5-15.2 FPS, 20,000 chunks of length 8.
    #
    # Retest with reworked halo/sphere shader, HUNK_SIZE = 5000     [setup time]
    # .  17,424 (132x132) spheres 52.8-53.7 FPS,  2,178 chunks of length 8. [60]
    # .  40,000 (200x200) spheres 29.3-30.4 FPS,  5,000 chunks of length 8.[156]
    # .  90,000 (300x300) spheres 18.2-19.2 FPS, 11,250 chunks of length 8.[381]
    # . 160,000 (400x400) spheres 10.2-11.6 FPS, 20,000 chunks of length 8.[747]
    # Billboard drawing patterns instead of cubes, HUNK_SIZE = 5000 [setup time]
    # .  17,424 (132x132) spheres 49.7-55.7 FPS,  2,178 chunks of length 8. [35]
    # .  40,000 (200x200) spheres 39.6-40.8 FPS,  5,000 chunks of length 8. [88]
    # .  90,000 (300x300) spheres 18.9-19.5 FPS, 11,250 chunks of length 8.[225]
    # . 160,000 (400x400) spheres 11.2-11.7 FPS, 20,000 chunks of length 8.[476]
    #
    elif int(testCase) == 8:
        doTransforms = False
        doCylinders = False
        if test_spheres is None:
            # Setup.
            print ("Test case 8, %d^2 primitives\n  %s, length %d." %
                   (nSpheres, "Short VBO/IBO chunk buffers", chunkLength))
            if testCase == 8.1:
                print ("Sub-test 8.1, sphere chunks are in CSDL's in a DrawingSet.")
                test_DrawingSet = DrawingSet()
            elif testCase == 8.2:
                print ("Sub-test 8.2, spheres, rotate with TransformControls.")
                test_DrawingSet = DrawingSet()
                doTransforms = True
            elif testCase == 8.3:
                print ("Sub-test 8.3, cylinder chunks are in CSDL's in a DrawingSet.")
                test_DrawingSet = DrawingSet()
                doCylinders = True
                pass
            if test_DrawingSet:
                # note: doesn't happen in test 8.0, which causes a bug then. [bruce 090223 comment]
                print "constructed test_DrawingSet =", test_DrawingSet

            if USE_GRAPHICSMODE_DRAW:
                print ("Use graphicsMode.Draw_model for DrawingSet in paintGL.")
                pass

            t1 = time.time()

            if doTransforms:
                # Provide several TransformControls to test separate action.
                global numTCs, TCs
                numTCs = 3
                TCs = [TransformControl() for i in range(numTCs)]
                pass

            def primCSDL(centers, radii, colors):
                if not doTransforms:
                    csdl = ColorSortedDisplayList() # Transformless.
                else:
                    # Test pattern for TransformControl usage - vertical columns
                    # of TC domains, separated by X coord of first center point.
                    # Chunking will be visible when transforms are changed.
                    xCoord = centers[0][0] - start_pos[0] # Negate centering X.
                    xPercent = (xCoord /
                                (nSpheres + nSpheres/10 +
                                 nSpheres/100 - 1 + (nSpheres <= 1)))
                    xTenth = int(xPercent * 10 + .5)
                    csdl = ColorSortedDisplayList(TCs[xTenth % numTCs])
                    pass

                # Test selection using the CSDL glname.
                ColorSorter.pushName(csdl.glname)
                ColorSorter.start(glpane, csdl)
                for (color, center, radius) in zip(colors, centers, radii):
                    if not doCylinders:
                        # Through ColorSorter to the sphere primitive buffer...
                        drawsphere(color, center, radius,
                                   DRAWSPHERE_DETAIL_LEVEL)
                    else:
                        # Through ColorSorter to cylinder primitive buffer...
                        if not drawing_globals.cylinderShader_available():
                            print "warning: not cylinderShader_available(), error is likely:"
                        if (True and  # Whether to do tapered shader-cylinders.
                            # Display List cylinders don't support taper.
                            glpane.glprefs.cylinderShader_desired()):
                            ###cylRad = (radius/2.0, (.75-radius)/2.0)
                            cylRad = (radius/1.5 - .167, .3 - radius/1.5)
                        else:
                            cylRad = radius/2.0
                            pass
                        endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5)
                        drawcylinder(color, center, endPt2, cylRad)
                        global test_endpoints
                        test_endpoints += [(center, endPt2)]
                        pass
                    continue
                ColorSorter.popName()
                ColorSorter.finish(draw_now = True)

                test_DrawingSet.addCSDL(csdl)
                return csdl

            if testCase == 8:
                #bruce 090223 revised to try to avoid traceback
                def chunkFn(centers, radii, colors):
                    res = GLSphereBuffer()
                    res.addSpheres(centers, radii, colors, None, None)
                    return res
                pass
            else:
                chunkFn = primCSDL
                pass

            test_spheres = []
            radius = .5
            centers = []
            radii = []
            colors = []
            global test_endpoints
            test_endpoints = []

            for x in range(nSpheres):
                for y in range(nSpheres):
                    centers += [sphereLoc(x, y)]

                    # Sphere radii progress from 3/4 to full size.
                    t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction.
                    thisRad = radius * (.5 + t*.5)
                    radii += [thisRad]

                    # Colors progress from red to blue.
                    colors += [rainbow(t)]

                    # Put out short chunk buffers.
                    if len(centers) >= chunkLength:
                        test_spheres += [
                            chunkFn(centers, radii, colors) ]
                        centers = []
                        radii = []
                        colors = []
                    continue
                continue
            # Remainder fraction buffer.
            if len(centers):
                test_spheres += [chunkFn(centers, radii, colors)]
                pass
            print "Setup time", time.time() - t1, "seconds."
            print "%d chunk buffers" % len(test_spheres)
            pass
        elif not initOnly: # Run.
            test_Draw_8x(glpane)
        pass
    elif testCase == 100: #bruce 090102
        # before making more of these, modularize it somehow
        from commands.TestGraphics.test_selection_redraw import test_selection_redraw
        test_class = test_selection_redraw
        params = ( nSpheres, )
            # note: test size is not directly comparable to other tests with same value of nSpheres
        if test_Object is None \
           or not isinstance(test_Object, test_class) \
           or test_Object.current_params() != params: # review: same_vals?
            # Setup.
            if test_Object:
                test_Object.destroy()
            test_Object = test_class(*params)
            test_Object.activate()
            print test_Object
            pass
        # review: safe to change elif to if? not sure, GL state is only initialized below
        elif not initOnly: # Run.
            test_Object.draw_complete()
            pass
        pass

    if not initOnly:
        glMatrixMode(GL_MODELVIEW)
        glFlush()
        pass

    first_time = False
    return
예제 #22
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
예제 #23
0
파일: Rect.py 프로젝트: elfion/nanoengineer
 def draw(self):
     drawsphere(self.fix_color(self.color), self.center, self.radius,
                self.detailLevel)
    def _drawSpecialIndicators(self):
        """
        Overrides superclass method.

        This draws a transparent cylinder around the segments being resized, to
        easily distinguish them from other model.

        @see: basicGraphicsmode._drawSpecialIndicators()

        """
        if self.command:

            if DEBUG_DRAW_SPHERES_AROUND_ATOMS_AT_BREAK_SITES:
                breakSitesDict = self._breakSite_marker.getBreakSitesDict()

                atmList = breakSitesDict.values()

                for atm in atmList:
                    sphere_radius = max(1.2*atm.drawing_radius(),
                                        SPHERE_RADIUS)
                    drawsphere(darkgreen,
                               atm.posn(),
                               sphere_radius,
                               SPHERE_DRAWLEVEL,
                               opacity = SPHERE_OPACITY)

            breakSites_atomPairs_dict = self._breakSite_marker.getBreakSites_atomPairsDict()

            for aDict in breakSites_atomPairs_dict.values(): #DEBUG========
                for atm1, atm2 in aDict.values():
                    #Its okay to do this check for only atm1 (for speed reason)
                    #lets assume that atm2 drawing radius will be the same (it won't
                    #be the same in very rare cases....)
                    cyl_radius = max(1.3*atm1.drawing_radius(),
                                     CYL_RADIUS)

                    drawcylinder(red,
                                 atm1.posn(),
                                 atm2.posn(),
                                 cyl_radius,
                                 capped = True,
                                 opacity = CYL_OPACITY )

            startAtomsDict = self._breakSite_marker.getStartAtomsDict()

            for atm in startAtomsDict.values():
                sphere_radius = max(1.2*atm.drawing_radius(),
                                    SPHERE_RADIUS_2)
                color = atm.molecule.color
                if color is None:
                    color = banana

                atom_radius = atm.drawing_radius()
                cyl_radius = 0.5*atom_radius
                cyl_height = 2.5*atom_radius
                axis_atm = atm.axis_neighbor()
                direction = None
                if axis_atm:
                    #Direction will be opposite of
                    direction = norm( atm.posn() - axis_atm.posn())

                draw3DFlag(self.glpane,
                           color,
                           atm.posn(),
                           cyl_radius,
                           cyl_height,
                           direction = direction,
                           opacity = 0.8)
    def _drawDnaRubberbandLine(self):
        """
        Overrides superclass method. It loops through the segments being resized
        and draws the rubberband lines for all. NOT this could be SLOW
        @see: MultipleDnaSegmentResize_EditCommand.getDnaRibbonParams() for 
              comments.
        @TODO: needs more cleanup
        """

        handleType = ''
        if self.command.grabbedHandle is not None:
            if self.command.grabbedHandle in [self.command.rotationHandle1, 
                                              self.command.rotationHandle2]:
                handleType = 'ROTATION_HANDLE'
            else:
                handleType = 'RESIZE_HANDLE'

        if handleType and handleType == 'RESIZE_HANDLE': 
            for segment in self.command.getResizeSegmentList():  
                self.command.currentStruct = segment
                params_when_adding_bases, params_when_removing_bases = \
                                        self.command.getDnaRibbonParams()  

                self.command.currentStruct = None
                if params_when_adding_bases:                    
                    numberOfBasePairs,\
                                    end1, \
                                    end2, \
                                    basesPerTurn,\
                                    duplexRise, \
                                    ribbon1_start_point, \
                                    ribbon2_start_point, \
                                    ribbon1_direction, \
                                    ribbon2_direction, \
                                    ribbon1Color, \
                                    ribbon2Color = params_when_adding_bases 


                    #Note: The displayStyle argument for the rubberband line should 
                    #really be obtained from self.command.struct. But the struct 
                    #is a DnaSegment (a Group) and doesn't have attr 'display'
                    #Should we then obtain this information from one of its strandChunks?
                    #but what if two strand chunks and axis chunk are rendered 
                    #in different display styles? since situation may vary, lets 
                    #use self.glpane.displayMode for rubberbandline displayMode
                    drawDnaRibbons(self.glpane,
                                   end1,
                                   end2,
                                   basesPerTurn,
                                   duplexRise,
                                   self.glpane.scale,
                                   self.glpane.lineOfSight,
                                   self.glpane.displayMode,
                                   ribbonThickness = 4.0,
                                   ribbon1_start_point = ribbon1_start_point,
                                   ribbon2_start_point = ribbon2_start_point,
                                   ribbon1_direction = ribbon1_direction,
                                   ribbon2_direction = ribbon2_direction,
                                   ribbon1Color = ribbon1Color,
                                   ribbon2Color = ribbon2Color,
                                   stepColor = black ) 
                    
                    #Draw a sphere that indicates the current position of 
                    #the resize end of each segment . 
                    drawsphere(env.prefs[selectionColor_prefs_key], 
                               end2, 
                               SPHERE_RADIUS_2,
                               SPHERE_DRAWLEVEL,
                               opacity = SPHERE_OPACITY) 
                    
                    numberOfBasePairsString = "+" + str(numberOfBasePairs)
                    self.glpane.renderTextAtPosition( end2, 
                                                      numberOfBasePairsString)
                
                elif params_when_removing_bases:
                    numberOfBasePairs , end2 = params_when_removing_bases
                    #Draw a sphere that indicates the current position of 
                    #the resize end of each segment.
                    drawsphere(darkred, 
                               end2, 
                               SPHERE_RADIUS_2,
                               SPHERE_DRAWLEVEL,
                               opacity = SPHERE_OPACITY)   
                    
                    numberOfBasePairsString = str(numberOfBasePairs)
                    self.glpane.renderTextAtPosition( end2, 
                                                      textString = numberOfBasePairsString,
                                                      )

                #Draw the text next to the cursor that gives info about 
                #number of base pairs etc
                self._drawCursorText()
예제 #26
0
    def drawchunk(self, glpane, chunk, memo, highlighted):
        """
        Draws reduced representation of a protein chunk.
        """

        structure, total_length, ca_list, n_sec = memo

        style = self.proteinStyle
        scaleFactor = self.proteinStyleScaleFactor
        resolution = self.proteinStyleQuality
        scaling = self.proteinStyleScaling
        smooth = self.proteinStyleSmooth

        gleSetJoinStyle(TUBE_JN_ANGLE | TUBE_NORM_PATH_EDGE | TUBE_JN_CAP | TUBE_CONTOUR_CLOSED ) 

        current_sec = 0
        for sec, secondary in structure:
            # Number of atoms in SS element including dummy atoms.
            n_atoms = len(sec) 
            # The length should be at least 3.
            if n_atoms >= 3:
                # Alpha carbon trace styles. Simple but fast.
                if style == PROTEIN_STYLE_CA_WIRE or \
                   style == PROTEIN_STYLE_CA_CYLINDER or \
                   style == PROTEIN_STYLE_CA_BALL_STICK:
                    for n in range( 1, n_atoms-2 ):
                        pos0, ss0, aa0, idx0, dpos0, cbpos0 = sec[n - 1]
                        pos1, ss1, aa1, idx1, dpos1, cbpos1 = sec[n]
                        pos2, ss2, aa2, idx2, dpos2, cbpos2 = sec[n + 1]
                        color = self._get_aa_color(chunk, 
                                                   idx1, 
                                                   total_length, 
                                                   ss1, 
                                                   aa1,
                                                   current_sec,
                                                   n_sec)
                        if style == PROTEIN_STYLE_CA_WIRE:
                            if pos0:
                                drawline(color, 
                                         pos1 + 0.5 * (pos0 - pos1), 
                                         pos1,
                                         width=5,
                                         isSmooth=True)
                            if pos2:
                                drawline(color, 
                                         pos1, 
                                         pos1 + 0.5 * (pos2 - pos1),
                                         width=5, 
                                         isSmooth=True)
                        else:
                            if pos0:
                                drawcylinder(color, 
                                             pos1 + 0.5 * (pos0 - pos1), 
                                             pos1,
                                             0.25 * scaleFactor, 
                                             capped=1)

                            if style == PROTEIN_STYLE_CA_BALL_STICK:
                                drawsphere(color, pos1, 0.5 * scaleFactor, 2)
                            else:
                                drawsphere(color, pos1, 0.25 * scaleFactor, 2)

                            if pos2:
                                drawcylinder(color, 
                                             pos1, 
                                             pos1 + 0.5 * (pos2 - pos1),
                                             0.25 * scaleFactor, 
                                             capped=1)

                elif style == PROTEIN_STYLE_PEPTIDE_TILES:
                    for n in range( 1, n_atoms-2 ):
                        pos0, ss0, aa0, idx0, dpos0, cbpos0 = sec[n - 1]
                        pos1, ss1, aa1, idx1, dpos1, cbpos1 = sec[n]
                        color = self._get_aa_color(chunk, 
                                                   idx1, 
                                                   total_length, 
                                                   ss1, 
                                                   aa1,
                                                   current_sec,
                                                   n_sec)
                        tri = []
                        nor = []
                        col = []


                elif style == PROTEIN_STYLE_TUBE or \
                     style == PROTEIN_STYLE_LADDER or \
                     style == PROTEIN_STYLE_ZIGZAG or \
                     style == PROTEIN_STYLE_FLAT_RIBBON or \
                     style == PROTEIN_STYLE_SOLID_RIBBON or \
                     style == PROTEIN_STYLE_SIMPLE_CARTOONS or \
                     style == PROTEIN_STYLE_FANCY_CARTOONS:

                    tube_pos = []
                    tube_col = []
                    tube_rad = []
                    tube_dpos = []

                    for n in range( 2, n_atoms-2 ):
                        pos00, ss00, a00, idx00, dpos00, cbpos00 = sec[n - 2]
                        pos0, ss0, aa0, idx0, dpos0, cbpos0 = sec[n - 1]
                        pos1, ss1, aa1, idx1, dpos1, cbpos1 = sec[n]
                        pos2, ss2, aa2, idx2, dpos2, cbpos2 = sec[n + 1]
                        pos22, ss22, aa22, idx22, dpos22, cbpos22 = sec[n + 2]

                        color = self._get_aa_color(chunk, 
                                                   idx1, 
                                                   total_length, 
                                                   ss1, 
                                                   aa1,
                                                   current_sec,
                                                   n_sec)

                        rad = 0.25 * scaleFactor
                        if style == PROTEIN_STYLE_TUBE and \
                           scaling == 1:
                            if secondary > 0: 
                                rad *= 2.0

                        if n == 2:
                            if pos0:
                                tube_pos.append(pos00)
                                tube_col.append(V(color))
                                tube_rad.append(rad)
                                tube_dpos.append(dpos1)
                                tube_pos.append(pos0)
                                tube_col.append(V(color))
                                tube_rad.append(rad)
                                tube_dpos.append(dpos1)


                        if style == PROTEIN_STYLE_LADDER:
                            drawcylinder(color, pos1, cbpos1, rad * 0.75)
                            drawsphere(color, cbpos1, rad * 1.5, 2)

                        if pos1:
                            tube_pos.append(pos1)
                            tube_col.append(V(color))
                            tube_rad.append(rad)
                            tube_dpos.append(dpos1)

                        if n == n_atoms - 3:
                            if pos2:
                                tube_pos.append(pos2)
                                tube_col.append(V(color))
                                tube_rad.append(rad)
                                tube_dpos.append(dpos1)
                                tube_pos.append(pos22)
                                tube_col.append(V(color))
                                tube_rad.append(rad)
                                tube_dpos.append(dpos1)

                    # For smoothed helices we need to add virtual atoms
                    # located approximately at the centers of peptide bonds
                    # but slightly moved away from the helix axis.

                    new_tube_pos = []
                    new_tube_col = []
                    new_tube_rad = []
                    new_tube_dpos = []
                    if smooth and \
                       secondary == 1:
                        for p in range(len(tube_pos)):
                            new_tube_pos.append(tube_pos[p])
                            new_tube_col.append(tube_col[p])
                            new_tube_rad.append(tube_rad[p])                        
                            new_tube_dpos.append(tube_dpos[p])

                            if p > 1 and p < len(tube_pos) - 3:
                                pv = tube_pos[p-1] - tube_pos[p]
                                nv = tube_pos[p+2] - tube_pos[p+1]
                                mi = 0.5 * (tube_pos[p+1] + tube_pos[p])
                                # The coefficient below was handpicked to make  
                                # the helices approximately round.
                                mi -= 0.75 * norm(nv+pv)                            
                                new_tube_pos.append(mi)
                                new_tube_col.append(0.5*(tube_col[p]+tube_col[p+1]))
                                new_tube_rad.append(0.5*(tube_rad[p]+tube_rad[p+1]))                        
                                new_tube_dpos.append(0.5*(tube_dpos[p]+tube_dpos[p+1]))

                        tube_pos = new_tube_pos
                        tube_col = new_tube_col
                        tube_rad = new_tube_rad
                        tube_dpos = new_tube_dpos

                    if secondary != 1 or \
                       style != PROTEIN_STYLE_SIMPLE_CARTOONS:
                        tube_pos, tube_col, tube_rad, tube_dpos = make_tube(
                            tube_pos, 
                            tube_col, 
                            tube_rad, 
                            tube_dpos, 
                            resolution=resolution)

                        if style == PROTEIN_STYLE_ZIGZAG or \
                           style == PROTEIN_STYLE_FLAT_RIBBON or \
                           style == PROTEIN_STYLE_SOLID_RIBBON or \
                           style == PROTEIN_STYLE_SIMPLE_CARTOONS or \
                           style == PROTEIN_STYLE_FANCY_CARTOONS:

                            last_pos = None
                            last_width = 1.0
                            reset = False

                            # Find SS element widths and determine width increment.
                            if secondary == 0:
                                # Coils have a constant width.
                                width = scaleFactor * 0.1
                                dw = 0.0
                            elif secondary == 1:
                                # Helices expand and shrink at the ends.
                                width = scaleFactor * 0.1
                                dw = (1.0 * scaleFactor) / (resolution - 3)
                            else:
                                # Strands just shrink at the C-terminal end.
                                width = scaleFactor * 1.0
                                dw = (1.6 * scaleFactor) / (1.5 * resolution - 3)

                            if style == PROTEIN_STYLE_FLAT_RIBBON or \
                               style == PROTEIN_STYLE_SOLID_RIBBON or \
                               style == PROTEIN_STYLE_SIMPLE_CARTOONS or \
                               style == PROTEIN_STYLE_FANCY_CARTOONS:

                                tri_arr0 = []
                                nor_arr0 = []
                                col_arr0 = []

                                if style == PROTEIN_STYLE_SOLID_RIBBON or \
                                   style == PROTEIN_STYLE_SIMPLE_CARTOONS or \
                                   style == PROTEIN_STYLE_FANCY_CARTOONS: 

                                    tri_arr1 = []
                                    nor_arr1 = []
                                    col_arr1 = []

                                    tri_arr2 = []
                                    nor_arr2 = []
                                    col_arr2 = []

                                    tri_arr3 = []
                                    nor_arr3 = []
                                    col_arr3 = []

                            from copy import copy
                            new_tube_dpos = copy(tube_dpos)

                            for n in range(1, len(tube_pos)-1):
                                pos = tube_pos[n]

                                col = tube_col[n][0]
                                col2 = tube_col[n+1][0]
                                if last_pos:
                                    next_pos = tube_pos[n+1]
                                    dpos1 = last_width * tube_dpos[n-1]
                                    dpos2 = width * tube_dpos[n]
                                    ddpos = dpos1-dpos2
                                    if reset:
                                        dpos1 = dpos2
                                        reset = False

                                    if self.proteinStyle == PROTEIN_STYLE_ZIGZAG:
                                        drawline(col, last_pos-dpos1, pos-dpos2, width=3)
                                        drawline(col, last_pos+dpos1, pos+dpos2, width=3)
                                        drawline(col, last_pos-dpos1, pos+dpos2, width=1)
                                        drawline(col, pos-dpos2, pos+dpos2, width=1)
                                        drawline(col, last_pos-dpos1, last_pos+dpos1, width=1)

                                    if self.proteinStyle == PROTEIN_STYLE_FLAT_RIBBON:
                                        if pos != last_pos:

                                            nvec1 = norm(cross(dpos1, pos-last_pos))
                                            if next_pos != pos:
                                                nvec2 = norm(cross(dpos2, next_pos-pos))
                                            else:
                                                nvec2 = nvec1

                                            nor_arr0.append(nvec1)
                                            nor_arr0.append(nvec1)
                                            nor_arr0.append(nvec2)
                                            nor_arr0.append(nvec2)

                                            tri_arr0.append(last_pos-dpos1) 
                                            tri_arr0.append(last_pos+dpos1)
                                            tri_arr0.append(pos-dpos2) 
                                            tri_arr0.append(pos+dpos2)

                                            col_arr0.append(col)
                                            col_arr0.append(col)
                                            col_arr0.append(col2)
                                            col_arr0.append(col2)

                                    if self.proteinStyle == PROTEIN_STYLE_SOLID_RIBBON or \
                                       self.proteinStyle == PROTEIN_STYLE_SIMPLE_CARTOONS or \
                                       self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS:

                                        if secondary > 0:

                                            col3 = col4 = V(gray)

                                            if pos != last_pos:

                                                nvec1 = norm(cross(dpos1, pos-last_pos))
                                                if next_pos != pos:
                                                    nvec2 = norm(cross(dpos2, next_pos-pos))
                                                else:
                                                    nvec2 = nvec1

                                                nor_arr0.append(nvec1)
                                                nor_arr0.append(nvec1)
                                                nor_arr0.append(nvec2)
                                                nor_arr0.append(nvec2)

                                                if self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS:
                                                    dn1 = 0.15 * nvec1 * scaleFactor
                                                    dn2 = 0.15 * nvec2 * scaleFactor
                                                else:
                                                    dn1 = 0.15 * nvec1 * scaleFactor
                                                    dn2 = 0.15 * nvec2 * scaleFactor

                                                tri_arr0.append(last_pos - dpos1 - dn1) 
                                                tri_arr0.append(last_pos + dpos1 - dn1)
                                                tri_arr0.append(pos - dpos2 - dn2) 
                                                tri_arr0.append(pos + dpos2 - dn2)

                                                col_arr0.append(col)
                                                col_arr0.append(col)
                                                col_arr0.append(col2)
                                                col_arr0.append(col2)

                                                nor_arr1.append(nvec1)
                                                nor_arr1.append(nvec1)
                                                nor_arr1.append(nvec2)
                                                nor_arr1.append(nvec2)

                                                tri_arr1.append(last_pos - dpos1 + dn1) 
                                                tri_arr1.append(last_pos + dpos1 + dn1)
                                                tri_arr1.append(pos - dpos2 + dn2) 
                                                tri_arr1.append(pos + dpos2 + dn2)

                                                if secondary == 1:
                                                    col_arr1.append(0.5 * col + 0.5 * V(white))
                                                    col_arr1.append(0.5 * col + 0.5 * V(white))
                                                    col_arr1.append(0.5 * col2 + 0.5 * V(white))
                                                    col_arr1.append(0.5 * col2 + 0.5 * V(white))
                                                else:
                                                    col_arr1.append(col)
                                                    col_arr1.append(col)
                                                    col_arr1.append(col2)
                                                    col_arr1.append(col2)

                                                nor_arr2.append(-dpos1)
                                                nor_arr2.append(-dpos1)
                                                nor_arr2.append(-dpos2)
                                                nor_arr2.append(-dpos2)

                                                tri_arr2.append(last_pos - dpos1 - dn1) 
                                                tri_arr2.append(last_pos - dpos1 + dn1)
                                                tri_arr2.append(pos - dpos2 - dn2) 
                                                tri_arr2.append(pos - dpos2 + dn2)

                                                col_arr2.append(col3)
                                                col_arr2.append(col3)
                                                col_arr2.append(col4)
                                                col_arr2.append(col4)

                                                nor_arr3.append(-dpos1)
                                                nor_arr3.append(-dpos1)
                                                nor_arr3.append(-dpos2)
                                                nor_arr3.append(-dpos2)

                                                tri_arr3.append(last_pos + dpos1 - dn1) 
                                                tri_arr3.append(last_pos + dpos1 + dn1)
                                                tri_arr3.append(pos + dpos2 - dn2) 
                                                tri_arr3.append(pos + dpos2 + dn2)

                                                col_arr3.append(col3)
                                                col_arr3.append(col3)
                                                col_arr3.append(col4)
                                                col_arr3.append(col4)


                                last_pos = pos
                                last_width = width

                                if secondary == 1:
                                    if n > len(tube_pos) - resolution:
                                        width -= dw 
                                    elif width < 1.0 * scaleFactor:
                                        width += dw

                                if secondary == 2:
                                    if n == len(tube_pos) - 1.5 * resolution:
                                        width = scaleFactor * 1.6
                                        reset = True
                                    if n > len(tube_pos) - 1.5 * resolution:
                                        width -= dw 

                                new_tube_dpos[n] = width * tube_dpos[n]

                        ###drawcylinder(white, tube_pos[0], tube_pos[10], 1.0)

                        if self.proteinStyle == PROTEIN_STYLE_FLAT_RIBBON:
                            drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr0, nor_arr0, col_arr0)

                        if self.proteinStyle == PROTEIN_STYLE_SOLID_RIBBON or \
                           self.proteinStyle == PROTEIN_STYLE_SIMPLE_CARTOONS or \
                           self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS:
                            if secondary == 0:
                                drawpolycone_multicolor([0,0,0,-2], tube_pos, tube_col, tube_rad)
                            else:
                                if (secondary == 1 and self.proteinStyle == PROTEIN_STYLE_SOLID_RIBBON) or \
                                   secondary == 2:
                                    drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr0, nor_arr0, col_arr0)
                                    drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr1, nor_arr1, col_arr1)
                                    drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr2, nor_arr2, col_arr2)
                                    drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr3, nor_arr3, col_arr3)
                                    # Fill in the strand N-terminal end.
                                    quad_tri = []
                                    quad_nor = []
                                    quad_col = []
                                    quad_tri.append(tri_arr2[0])
                                    quad_tri.append(tri_arr3[0])
                                    quad_tri.append(tri_arr2[1])
                                    quad_tri.append(tri_arr3[1])
                                    quad_nor.append(nor_arr2[0])
                                    quad_nor.append(nor_arr3[0])
                                    quad_nor.append(nor_arr2[1])
                                    quad_nor.append(nor_arr3[1])
                                    quad_col.append(col_arr2[0])
                                    quad_col.append(col_arr3[0])
                                    quad_col.append(col_arr2[1])
                                    quad_col.append(col_arr3[1])
                                    drawtriangle_strip([1.0,1.0,1.0,-2.0],quad_tri,quad_nor,quad_col)

                                if (secondary == 1 and self.proteinStyle == PROTEIN_STYLE_FANCY_CARTOONS):
                                    drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr0, nor_arr0, col_arr0)
                                    drawtriangle_strip([1.0,1.0,0.0,-2.0], tri_arr1, nor_arr1, col_arr1)
                                    tube_pos_left = []
                                    tube_pos_right = []
                                    new_tube_dpos[0] *= 0.1
                                    new_tube_dpos[1] *= 0.2
                                    new_tube_dpos[-1] *= 0.1
                                    new_tube_dpos[-2] *= 0.2
                                    for p in range(len(tube_pos)):
                                        tube_pos_left.append(tube_pos[p] - new_tube_dpos[p])
                                        tube_pos_right.append(tube_pos[p] + new_tube_dpos[p])
                                        tube_rad[p] *= 0.75
                                    drawpolycone_multicolor([0,0,0,-2], tube_pos_left, tube_col, tube_rad)
                                    drawpolycone_multicolor([0,0,0,-2], tube_pos_right, tube_col, tube_rad)

#                    else:                               
                    if (secondary == 1 and style == PROTEIN_STYLE_SIMPLE_CARTOONS):
                        drawcylinder(tube_col[0][0], tube_pos[1], tube_pos[-3], 2.5, capped=1)
                        #print "hopsa"

                    if style == PROTEIN_STYLE_LADDER or \
                       style == PROTEIN_STYLE_TUBE:
                        # Draw tube.
                        drawpolycone_multicolor([0,0,0,-2], tube_pos, tube_col, tube_rad)

            # increase Sec. Str. element counter
            current_sec += 1