next up previous contents index
Next: Methods for Debugging Up: Writing Methods Previous: Refcount Handling

Display Methods

 

Another important category of methods are display methods. You should be familiar with the general interaction strategy of the GRAPE manager (see section 4.3.2): there is always a ``current display method'' which is used to update the graphics window. This method can be changed interactively, the default display method is "display". Therefore for a new geometry class you should at least implement this default display method, of course the "display" method of the superclass can be used via inheritance instead.

Display methods (beside "display") should always have the suffix "-disp", they must be parameterless. It is possible to use interactive elements like rulers to provide parameters for a display method as it is done in the example below. This will be explained in section 5.5.5.

As mentioned we could use the superclass method to display the Rot2d instances, but we would only see the surface of revolution and not the curve we are working on or the axis. Therefore we implement a "display" method for our new class, it draws curve, axis and surface and the point we are currently working on (the index of this point is stored in the instance variable current). For drawing the point an icosahedron is used, its ``radius'' can be controled by a ruler.

ROT2D *rot2d_display()
{
  ROT2D *self;
  TRIANG1D *curve;

  self = (ROT2D *)START_METHOD(G_INSTANCE);
  ASSURE(self, "", END_METHOD(NULL));

  /*
   * Before calling "display" on the curve to show it, we have
   * to check if we really have a curve with points. A curve with
   * no points would be no problem, but then the "display" is not
   * necessary. No curve is a problem, we would get an error
   * message "NULL object for method `display'".
   */
  if((curve = self->curve) && curve->number_of_points) {
    GRAPE(curve, "display")();

    /*
     * We want to see the point we edit, therefore we have to display
     * it in some way. Drawing a single point doesn't help much, there-
     * fore we draw a small icosahedron around the point. But first
     * lets check if there is a point in the curve with index current.
     */
    if(self->current >= 0 && self->current < curve->number_of_points) {
      /*
       * The ruler is defined static and initialized with NULL so that
       * we can detect if it was already created. The variable iparm
       * defines the "midpoint" and the "radius" for the icosahedron.
       */
      static double iparm[4] = { 0.0, 0.0, 0.0, 0.05 };
      static RULER *radius = NULL;
      MANAGER *mgr;

      /*
       * We have to create the ruler the first time this method is
       * called. It get the name and label "point radius" and the
       * variable it controls is the radius in iparm. The other
       * values define the layout of the ruler.
       */
      if(!radius)
        radius = (RULER *)new_item(Ruler, I_Name, "point radius",
                                   I_Var, &(iparm[3]), dfDouble,
                                   I_MinMax, 1.e-5, 0.25, I_Scale, 0.25,
                                   I_Offset, 0.0, I_StepSize, 0.025, I_End);

      /*
       * The standard manager is the object that controls the two
       * windows you get when grape is started.
       */
      mgr = (MANAGER *)GRAPE(Manager, "get-stdmgr")();

      /*
       * We have to tell the manager that we want our ruler displayed
       * when this method is active. We used "new-handle" to tell the
       * manager that the object put into the manager by "add-inter"
       * that follows the "new-handle" belongs to rot2d_display. The
       * `1' indicates that we include one object into the manager.
       */
      if(radius && mgr && GRAPE(mgr, "new-handle")(rot2d_display, 1))
        GRAPE(mgr, "add-inter")(radius);

      /*
       * Now copy the coordinates of the current curve point to the
       * array that is used to get an icosahedron at the position
       * and with the radius defined by iparm.
       */
      iparm[0] = curve->x[self->current];
      iparm[1] = curve->y[self->current];
      iparm[2] = curve->z[self->current];

      /*
       * get_icosaeder returns a Triang2d instance which we can
       * display with the standard "display" method.
       */
      GRAPE(get_icosaeder(iparm), "display")();
    }
  }

  /*
   * As for the curve we only call "display" on the axis if we
   * really have one.
   */
  if(self->axis && self->axis->number_of_points)
    GRAPE(self->axis, "display")();

  /*
   * Upto now we have only drawn the axis and the curve. To draw
   * the surface itself we just call "display" on the superclass
   * Triang2d.
   */
  GRAPE(self, "^display")();

  /*
   * Everything was ok, so we return the instance.
   */
  END_METHOD(self);
}

In this example we were able to use already existing display methods ("display" on Triang1d and Triang2d) to draw the objects. If you want to draw lines and/or (shaded) patches yourself the standard graphicdevice (the graphic window is an instance of class GraphicDevice) can be used, see section 9.2.2.



SFB 256 Universität Bonn and IAM Universität Freiburg

Copyright © by the Sonderforschungsbereich 256 at the Institut für Angewandte Mathematik, Universität Bonn.