From: Andrew Dalke (dalke_at_mag.com)
Date: Wed Nov 19 1997 - 08:03:35 CST

Nithin asked about drawing spheres in VMD:

> I've extracted x,y,z co-ordinates and radius of the beads and would
> now lie to display them on the VMD GUI.

  I wrote everything below (after the next >quote) on the assumption
that you wanted to add a new representation type for VMD. Now I see
you want something quite different, I think. I keep the original
answer since I don't like seeing electrons going to waste :)

  You should take a look at the text command for "draw" or "graphics."
They allow you to easily add new primitives to the display without
having to change the underlying C++ code at all. For example, suppose
your file is a set of {x,y,z,r} coordinates. Here's a function you
can define (just copy and paste into the VMD text terminal) to display
the coordinates.

proc load_spheres {filename} {
  # create the new graphics molecule
  set infile [open $filename r]
  mol new graphics "From $filename"
  set molid [molinfo top]

  while {[gets $infile line] >= 0} {
    lassign $line x y z r
    graphics $molid sphere [list $x $y $z] radius $r
  }
  close $infile
}

Then to use it, type

   load_spheres points.dat

(You will probably have to reset the view after this, control-r or use
the popup menu.)

You can also change the colors pretty easily. These commands are
all described in the user's manual.

You can pretty much ignore the following:
> I'd like to use
>
> cmdSphereIndex.putdata(3*i, radius, this);
>
> except i've no idea how this structure-function is used ??
>
> I guess i'm not going to find something like drawSphere(x,y,z,r);

  You actually want a DispCmdSphere instead of a DispCmdSphereIndex.
You could actually do something like

#define drawSphere(x,y,z,r) { \
  DispCmdSphere cmdSphere; \
  float tmp_coord[3]; tmp_coord[0] = x; \
  tmp_coord[1] = y; tmp_coord[2] = z; \
   cmdSphere.putdata(tmp_coord, r, this); \
}

to get what you want, but it would be a bit slower than it need be.

There are a few things going on. The big point is that each
Displayable object (a Molecule, the Axes, etc.) has its own display
list which contains a list of graphics tokens (sphere, cylinder, etc.)
used during the rendering process, which occurs later. Thus, when you
add a new graphics token, that method needs to know the Displayable to
which to add the token. That is why the last option (the 'this')
exists.

I don't think you want to get into much of a discussion of how this
might "best" be done in C++; eg, there are ways to make the 'this' not
needed by using multiple inheritance, or we might have used global
instances (as it is, you have to create an instance of DispCmdSphere
before you can draw anything).

  But you do want to know the difference between DispCmdSphere and
DispCmdSphereIndex. We tried different ways to organize the graphics.
For example, imagine just drawing points for each atom, and each point
is pickable with the mouse. For the ones that are visible, you have
to store a list of coordinates for the point and a list of coordinates
for the pickpoint. This calls for 2*(3*N{visible}) storage.
  Instead, you could store a list of coordinates and use that list for
both the graphics points and the pick points. You end up needing an
index into the original table, and the way we did it requires
3*N{total} + 2*N{visible} storage, assuming sizeof(int)==sizeof(float).
(You could reduce this to (3+2)*N.)
   So there is a way to save space for some types of graphics (tmesh
surfaces would save even more space). The "index" versions of the
graphics functions are all designed to work back into a vertex list
set previously.

  But for the items you are working on, don't worry about using the
indexed versions; the normal ones are fine.

  The other things that might confuse you is the difference between a
"putdata" and a "reputdata". There is a reason for them, but don't
worry about it; just use the putdata and everything is fine.

> Could someone please tell me the best procedure for drawing spheres.

Here's one way to reimplement the vdw spheres code; but it is
untested. I assume this method is a member function of DrawMolItem so
some of the objects are declared in class scope.

void DrawMolItem::draw_spheres(float *framepos)
{
  DispCmdSphere cmdSphere; // Should be put in DrawMolItem.h
  int lastcolor = -1;

  if (!framepos) return; // simple error check for coordinate list

  // Add a comment token to the drawing list for use when making
  // output for things like POV-Ray. Useful for postprocessing of
  // the output by people or other programs.
  sprintf (commentBuffer,"MoleculeID: %d ReprID: %d Beginning Spheres",
         mol->id(), repNumber);
  cmdCommentX.putdata(commentBuffer, this);

  // get the sphere resolution and scale based on the current
  // AtomRep settings
  float sphere_scale = atomRep->sphere_rad();
  float sphere_resolution = atomRep -> sphere_res();
  if (sphere_scale <= 0) return; // don't draw 0 scaled spheres

  // add resolution information to the drawing list token
  cmdSphres.putdata(sphere_resolution, this);
  // and we are going to draw a solid sphere
  cmdSphtype.putdata(SOLIDSPHERE, this);

  // now draw sphere for each selected atom
  // check all atoms if they are displayed, and if so draw a sphere
  for(i=0; i < mol->nAtoms; i++) {
    if(atomSel->on[i]) {
      // set color (don't change the color if I don't have to)
      // This is a performance feature.
      if (lastcolor != atomColor -> color[i]) {
        lastcolor = atomColor -> color[i];
        cmdColorIndex.putdata(lastcolor, this);
      }
      
      // draw sphere (pass {x,y,z}, r, and the Displayable)
      cmdSphere.putdata(framepos + 3*i,
                        (mol->atom(i))->radius() * sphere_scale,
                        this);

      // indicate this atom can be picked
      pickPointIndex.putdata(3*i, i, this);
    }
  }
}
  

                                                Andrew
                                                dalke_at_mag.com

---
Not speaking for the Molecular Applications Group.