Re: polyhedral cells

Hi Randy,
 
> > > ... if I want to display the underlying grid itself, it's going
> > > to take quite a bit of effort?
> >
> > It will take some.  It depends on how you want to see it.
> >
> > Do you want to see the edges of your cells?  That may not be
> > too difficult.  For a large number of cells those edges may
> > look pretty complex.
>
> As a first pass, I would like to display *all* polygonal faces of the
> cells, color-coded according to the scalar values at the vertices (actually,
> my field is cell-centered, but that's another problem).  If I display the cell
> faces as opaque polygons, then I'll see only the exterior faces of my 
> domain...
> with semi-transparency, I could peer into the interior a bit.
 
I'm going to post my description of how to write a custom dataRenderer
to the mailing list, in case others are interested and so that it will
be on Unidata's VisAD mailing list archive.
 
 
You need to extend two classes, DefaultRendererJ3D and
ShadowFunctionTypeJ3D, in the visad.java3d package (you should
extend ShadowFunctionTypeJ3D rather than ShadowSetTypeJ3D since
your data object is actually a Field rather than just a Set -
the Irregular3DSet you construct from your cells is the domain
Set of the Field).
 
You could put your new classes in a new package (visad.heiland?)
or you could put them right back in visad.java3d.
 
Here is the code for CellFaceRendererJ3D.java:
 
  package visad.java3d;
 
  import visad.*;
  import java.rmi.*;
  import javax.media.j3d.*;
 
  public class CellFaceRendererJ3D extends DefaultRendererJ3D {
 
    public CellFaceRendererJ3D() {
      super();
    }
 
    // override makeShadowFunctionType to use CellFaceShadowFunctionTypeJ3D
    public ShadowType makeShadowFunctionType(
           FunctionType type, DataDisplayLink link, ShadowType parent)
           throws VisADException, RemoteException {
      return new CellFaceShadowFunctionTypeJ3D(type, link, parent);
    }
 
  }
 
 
Here is the code for CellFaceShadowFunctionTypeJ3D.java (which
needs to be edited):
 
  package visad.java3d;
 
  import visad.*;
  import javax.media.j3d.*;
  import java.util.Vector;
  import java.util.Enumeration;
  import java.rmi.*;
 
  public class CellFaceShadowFunctionTypeJ3D extends ShadowFunctionTypeJ3D {
 
    public CellFaceShadowFunctionTypeJ3D(MathType t, DataDisplayLink link,
                                        ShadowType parent)
           throws VisADException, RemoteException {
      super(t, link, parent);
 
    }
 
    //
    // override doTransform to do the actual work
    //
    // the easiest way to way to do this is to copy the entire doTransform
    // method from ShadowFunctionOrSetTypeJ3D.java, and then edit it
    //
    public boolean doTransform(Group group, Data data, float[] value_array,
                               float[] default_values, DataRenderer renderer)
           throws VisADException, RemoteException {
 
      if (data.isMissing()) {
        ensureNotEmpty(group);
        return false;
      }
 
  . . . code omitted for brevity . . .
 
            // edit the following code (at about line 1418 in
            // ShadowFunctionOrSetTypeJ3D.java)
            else if (spatialManifoldDimension == 3) {
              array = makePointGeometry(spatial_values, color_values);
              // System.out.println("makePointGeometry  for 3D");
              //
              // when make3DGeometry is implemented:
              // array = spatial_set.make3DGeometry(color_values);
              //
            }
 
  . . . code omitted for brevity . . .
 
        ensureNotEmpty(group);
        return post;
  /*
        throw new UnimplementedException("ShadowFunctionOrSetType.doTransform: 
" +
                                         "not terminal");
  */
      } // end if (!isTerminal)
    }
 
  }
 
 
All the real work is in the code to replace the call to
makePointGeometry that constructs and returns a VisADGeometryArray.
The spatial_values array, organized as float[3][number_of_vertices],
contains the locations of all your cell vertices transformed to
graphics coordinates (determined from values of RealTypes mapped to
spatial DisplayRealTypes such as Display.XAxis, Display.YAXis, etc).
The color_values array, organized as float[3 or 4][number_of_vertices],
contains the color componments of all your cell vertices scaled to the
range (0.0f, 1.0f) (determined from values of RealTypes mapped to color
DisplayRealTypes such as Display.Red, Display.RGB, etc).  The
color_values array contains the (R, G, B) or the (R, G, B, A)
components, depending on whether its length is 3 or 4 (which in turn
depends on whether the application creates a ScalarMap to Display.Alpha).
 
Your code can get the cell topology from spatial_set, which will be
an Irregular3DSet if the domain Set of your Field is and if all its
RealType components are mapped to spatial DisplayRealTypes
(Display.XAxis, Display.YAxis, etc).  Get the topology as follows:
 
  if (!(spatial_set instanceof Irregular3DSet)) {
    throw new DisplayException("CellFaceShadowFunctionTypeJ3D " +
                               "requires Irregular3DSet");
  }
  Delaunay delan = ((Irregular3DSet) spatial_set).Delaunay;
  int[][] tri = delan.Tri;
 
Now tri is organized int[number_of_tetrahedra][4] and the faces you
want to render are each triple of vertices in each tetrahedron.  It
will be simplest to construct a VisADTriangleArray (extends
VisADGeometryArray and is much simpler than
VisADIndexedTriangleStripArray).  Use the values in the tri array as
indices into spatial_values and color_values to get the values for
the coordinates and colors arrays in the VisADTriangleArray.  You
will also need to compute values for the normals array (vector cross
product of two edges of the triangle).  Note that these arrays are
all organized float[number_of_triangles * 3 * 3] (except colors may
be organized float[number_of_triangles * 3 * 4] if there are alpha
transparency values).  That is, the coordinates array is organized:
 
  coordinates[0] = x coordinate for 1st vertex of 1st triangle
  coordinates[1] = y coordinate for 1st vertex of 1st triangle
  coordinates[2] = z coordinate for 1st vertex of 1st triangle
  coordinates[3] = x coordinate for 2nd vertex of 1st triangle
  coordinates[4] = y coordinate for 2nd vertex of 1st triangle
  coordinates[5] = z coordinate for 2nd vertex of 1st triangle
  coordinates[6] = x coordinate for 3rd vertex of 1st triangle
  coordinates[7] = y coordinate for 3rd vertex of 1st triangle
  coordinates[8] = z coordinate for 3rd vertex of 1st triangle
  coordinates[9] = x coordinate for 1st vertex of 2st triangle
  coordinates[10] = y coordinate for 1st vertex of 2st triangle
  etc
 
You also need to set vertexCount = 3 * number_of_triangles in
your VisADTriangleArray, but can ignore vertexFormat.
 
Note that the Delan variable in IrregularSet (inherited by
Irregular3DSet) was not public but I just made it so.  You can
either re-download VisAD, or simply change:
 
  Delaunay Delan = null;
 
to:
 
  public Delaunay Delan = null;
 
in visad/IrregularSet.java.
 
Also note that transparency rendering will be full of errors unless
the triangles in your VisADTriangleArray are sorted in depth order,
but that depth order changes depending on rotation angle and it is
completely computationally infeasible to re-sort triangles as the
scene is interactively rotated.  Hence, transparency may not look
very good with your data.
 
If you go ahead with this work, it would be great if you would make
your new classes available on a web page for others to use (I am sure
lots of people will find them useful).  We will make a link to your
page.  If this is a problem for you, we would be happy to serve your
classes - but I assume that web serving is no problem at NCSA ;)
 
I hope you do go ahead with this and please let me know if you have
any questions or problems.
 
Cheers,
Bill
 
----------------------------------------------------------
Bill Hibbard, SSEC, 1225 W. Dayton St., Madison, WI  53706
whibbard@xxxxxxxxxxxxx  608-263-4427  fax: 608-263-6738
http://www.ssec.wisc.edu/~billh/vis.html