Example #1
0
// To write an X3DOM-compatible scene file, we cannot include
// LineProperties nodes.
void X3DOMDisplayDevice::text(float *pos, float size, float thickness,
                               const char *str) {
  float textpos[3];
  float textsize;
  hersheyhandle hh;

  // transform the world coordinates
  (transMat.top()).multpoint3d(pos, textpos);
  textsize = size * 1.5f;

  ResizeArray<int>   idxs; 
  ResizeArray<float> pnts;
  idxs.clear();
  pnts.clear();

  int idx=0;
  while (*str != '\0') {
    float lm, rm, x, y;
    int draw;
    x=y=0.0f;
    draw=0;

    hersheyDrawInitLetter(&hh, *str, &lm, &rm);
    textpos[0] -= lm * textsize;

    while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
      float pt[3];

      if (draw) {
        // add another connected point to the line strip
        idxs.append(idx);

        pt[0] = textpos[0] + textsize * x;
        pt[1] = textpos[1] + textsize * y;
        pt[2] = textpos[2];

        pnts.append(pt[0]);
        pnts.append(pt[1]);
        pnts.append(pt[2]);

        idx++;
      } else {
        idxs.append(-1); // pen-up, end of the line strip
      }
    }
    idxs.append(-1); // pen-up, end of the line strip
    textpos[0] += rm * textsize;
    str++;
  }

  fprintf(outfile, "<Shape>\n");
  fprintf(outfile, "  ");

  // 
  // Emit the line properties
  // 
  fprintf(outfile, "<Appearance><Material ");
  fprintf(outfile, "ambientIntensity='%g' ", mat_ambient);
  fprintf(outfile, "diffuseColor='0 0 0' "); 

  const float *rgb = matData[colorIndex];
  fprintf(outfile, "emissiveColor='%g %g %g' ",
          mat_diffuse * rgb[0], mat_diffuse * rgb[1], mat_diffuse * rgb[2]);
  fprintf(outfile, "/>");

#if 0
  // XXX X3DOM v1.1 doesn't handle LineProperties nodes
  // emit a line thickness directive, if needed
  if (thickness < 0.99f || thickness > 1.01f) {
    fprintf(outfile, "  <LineProperties linewidthScaleFactor=\"%g\" "
            "containerField=\"lineProperties\"/>\n",
            (double) thickness);
  }
#endif
  fprintf(outfile, "</Appearance>\n");

  //
  // Emit the line set
  // 
  fprintf(outfile, "  <IndexedLineSet coordIndex='");
  int i, cnt;
  cnt = idxs.num();
  for (i=0; i<cnt; i++) {
    fprintf(outfile, "%d ", idxs[i]);
  }
  fprintf(outfile, "'>\n");

  fprintf(outfile, "    <Coordinate point='");
  cnt = pnts.num();
  for (i=0; i<cnt; i+=3) {
    fprintf(outfile, "%c%g %g %g", 
            (i==0) ? ' ' : ',',
            pnts[i], pnts[i+1], pnts[i+2]);
  }
  fprintf(outfile, "'/>\n");
  fprintf(outfile, "  </IndexedLineSet>\n");
  fprintf(outfile, "</Shape>\n");
}
// draw a 3-D field lines that follow the volume gradient
void
DrawMolItem::draw_volume_field_lines (int volid, float seedval, float minlen,
    float maxlen, float thickness)
{
  const VolumetricData * v = NULL;
  v = mol->get_volume_data (volid);
  int printdonemesg = 0;

  if (v == NULL)
  {
    msgInfo << "No volume data loaded at index " << volid << sendmsg;
    return;
  }

  int seedcount = 0;
  int pointcount = 0;
  int totalpointcount = 0;
  int usecolor;
  ResizeArray<float> seeds;

  append (DMATERIALOFF);
  usecolor = draw_volume_get_colorid ();
  cmdColorIndex.putdata (usecolor, cmdList);

  seedcount = calcseeds_gradient_magnitude (v, &seeds, seedval * 0.5f,
      seedval * 1.5f);

  // Integrate field lines starting with each of the seeds to simulate
  // particle advection.
  // Uses Euler's approximation for solving the initial value problem.
  // We could get a more accurate solution using a fourth order Runge-Kutta
  // method, but with more math per iteration.  We may want to implement 
  // the integrator as a user selected option.

  // The choice of integration step size is currently arbitrary,
  // but will become a user-defined parameter, since it affects speed
  // and accuracy.  A good default might be 0.25 times the smallest
  // grid cell spacing axis.
  float lx, ly, lz;
  v->cell_lengths (&lx, &ly, &lz);
  float mincelllen = lx;
  mincelllen = (mincelllen < ly) ? mincelllen : ly;
  mincelllen = (mincelllen < lz) ? mincelllen : lz;
  float delta = mincelllen * 0.25f; // delta per step (compensates gradient magnitude)

  // minimum gradient magnitude, before we consider that we've found
  // a critical point in the dataset.
  float mingmag = 0.0001f;

  // max gradient magnitude, before we consider it a source/sink
  float maxgmag = 5;

  ResizeArray<float> points;

  // For each seed point, integrate in both positive and
  // negative directions for a field line length up to
  // the maxlen criterion.
  msgtimer *msgt = msg_timer_create (1);
  int seed;
  for (seed = 0; seed < seedcount; seed++)
  {
    // emit UI messages as integrator runs, for long calculations...
    if (!(seed & 7) && msg_timer_timeout (msgt))
    {
      char tmpbuf[128];
      sprintf (tmpbuf, "%6.2f %% complete",
          (100.0f * seed) / (float) seedcount);
      msgInfo << "integrating " << seedcount << " field lines: " << tmpbuf
          << sendmsg;
      printdonemesg = 1;
    }

    int direction;
    for (direction = -1; direction != 1; direction = 1)
    {
      float pos[3], comsum[3];
      vec_copy (pos, &seeds[seed * 3]); // integration starting point is the seed

      // init the arrays
      points.clear ();

      // main integration loop
      pointcount = 0;
      totalpointcount++;
      float len = 0;
      int iterations = 0;
      float dir = (float) direction;

      vec_zero (comsum); // clear center of mass accumulator

      while ((len < maxlen) && (totalpointcount < 100000000))
      {
        float grad[3];

        // sample gradient at the current position
        v->voxel_gradient_interpolate_from_coord (pos, grad);

        // Early-exit if we run out of bounds (gradient returned will
        // be a vector of NANs), run into a critical point (zero gradient)
        // or a huge gradient at a source/sink point in the dataset.
        float gmag = norm (grad);
        if (gmag < mingmag || gmag > maxgmag)
          break;

        // Draw the current point only after the gradient value
        // has been checked, so we don't end up with out-of-bounds
        // vertices.
        // Only emit a fraction of integration points for display since
        // the integrator stepsize needs to be small for more numerical
        // accuracy, but the field lines themselves can be well 
        // represented with fewer sample points.
        if (!(iterations & 1))
        {
          // Add a vertex for this field line
          points.append (pos[0]);
          points.append (pos[1]);
          points.append (pos[2]);

          vec_incr (comsum, pos);

          pointcount++;
          totalpointcount++;
        }

        // adjust integration stepsize so we never move more than 
        // the distance specified by delta at each step, to compensate
        // for varying gradient magnitude
        vec_scaled_add (pos, dir * delta / gmag, grad); // integrate position
        len += delta; // accumulate distance

        iterations++;
      }

      int drawfieldline = 1;

      // only draw the field line for this seed if we have enough points.
      // If we haven't reached the minimum field line length, we'll
      // drop the whole field line.
      if (pointcount < 2 || len < minlen)
        drawfieldline = 0;

      // only draw if bounding sphere diameter exceeds minlen
      if (drawfieldline)
      {
        float com[3];
        vec_scale (com, 1.0f / (float) pointcount, comsum);
        float minlen2 = minlen * minlen;

        drawfieldline = 0;
        int p;
        for (p = 0; p < pointcount; p++)
        {
          if ((2.0f * distance2 (com, &points[p * 3])) > minlen2)
          {
            drawfieldline = 1;
            break;
          }
        }
      }

      // only draw the field line if it met all selection criteria
      if (drawfieldline)
      {
        cmdLineType.putdata (SOLIDLINE, cmdList);
        cmdLineWidth.putdata ((int) thickness, cmdList);
        cmdColorIndex.putdata (usecolor, cmdList);
        DispCmdPolyLineArray cmdPolyLineArray;
        cmdPolyLineArray.putdata (&points[0], pointcount, cmdList);
      }
    }
  }
  msg_timer_destroy (msgt);

  if (printdonemesg)
    msgInfo << "field line integration complete." << sendmsg;
}