IsoSurface Rendering of an AR Representation

rlaramee
Class IsoSurface

java.lang.Object
  |
  +--java.util.AbstractCollection
        |
        +--java.util.AbstractList
              |
              +--java.util.Vector
                    |
                    +--rlaramee.IsoSurface
All Implemented Interfaces:
java.lang.Cloneable, java.util.Collection, java.util.List, java.io.Serializable

public class IsoSurface
extends java.util.Vector

Description: An IsoSurface is the output of the Marching Cubes rendering algorithm. The IsoSurface is a set of triangles.

start date Sun 02 May 1999

Version:
1.0
Author:
Robert S Laramee
See Also:
, Serialized Form

Field Summary
private  Interpolator interpolator
           
private  IsoSurfaceAdaptive isoSurfaceAdaptive
           
private  float isoValue
          number of octree nodes/cubes in isosurface
private  MarchingCubes MC
          passed in order to use the generateTopologicalIndex() and getEdges() methods from the compareEdges() method
private  int numCubes
          number of octree nodes/cubes in isosurface
private  TriangleVertexList triangleVertexList
           
 
Fields inherited from class java.util.Vector
capacityIncrement, elementCount, elementData, serialVersionUID
 
Fields inherited from class java.util.AbstractList
modCount
 
Constructor Summary
IsoSurface(float isoVal, MarchingCubes mc)
          constructor
 
Method Summary
private  void addARverticesToNeighbor(OctreeNode coarseNode, SharedVertex[] vertices)
          This method is called from IsoSurface.processCoarserNeighbor()
 void addNode(OctreeNode node)
           addNode() adds a node, that has a triangle list, onto the IsoSurface.
private  boolean addSecondPassNode(OctreeNode coarseNode, boolean firstPass)
           
private  void addSingletons(OctreeNode coarseNode, SharedVertex[] vertices, boolean[] addSingleton)
          This method is called from IsoSurface.addARverticesToNeighbor()
 void addTriangle(Triangle triangle)
           addTriangle() adds a triangle onto the IsoSurface.
 Triangle addTriangleToSurface(OctreeNode node, int[] listIndices)
          This is called from IsoSurface.computeTriangle() and OctreeARnode.assembleTriangleFan()
 int[] addVerticesToVertexList(OctreeNode node, TriangleVertex[] vertices)
          This is called from IsoSurface.computeTriangle() and OctreeARnode.assembleTriangleFan()
private  int compareVertices(OctreeNode octreeNode, TriangleVertex newVertex)
          This method searches the given octree node's list of triangle vertices to see if one is the same as the given triangle vertex.
private  void computeTriangle(OctreeNode node, byte[] edges, byte[] uniqueEdges, boolean firstPass)
          Here's a edge to vertex pair mapping.
 void computeTriangles(OctreeNode node, byte[] edges, boolean firstPass)
          The computeTriangles() method creates a new triangle for each set of 3 edge intersections in the cube.
private  TriangleVertex computeVertex(OctreeNode node, byte edge)
          This method is called from IsoSurface.computeTriangle() .
private  boolean findARoctreeNodes(OctreeNode octreeNode, byte[] directions, TriangleVertex[] vertices, boolean firstPass)
          Note: IsoSurface.findARoctreeNodes() is called from IsoSurface.computeTriangle()
 int getActualNumVertices()
          This method is called from Gridded3DMRSet.makeIsoSurface()
 float[] getActualVisADcoords(int dimension)
          "Actual" means get each unique vertex out of the vertex list i.e.
(package private)  float[] getError()
          This hastily written method will return the error values associated with the surface points -PJR
 Interpolator getInterpolator()
           
private  IsoSurfaceAdaptive getIsoSurfaceAdaptive()
           
 float getIsoValue()
           
 MarchingCubes getMarchingCubes()
           
private  int getNumCubes()
           
 int getNumPolygons()
           
 Triangle getTriangle(int n)
           getTriangle() returns triangle, n , in the IsoSurface.
 TriangleVertexList getVertexList()
           
private  int inspectNeighbors(byte[] directions, OctreeNode octreeNode, TriangleVertex triangleVertex)
           
private  boolean isNew(byte[] uniqueEdges, byte edge)
           
 void print()
          Used for testing
 void processAdaptiveSurface()
          This is called from MarchingCubes.execute() (at the end)
private  boolean processCoarserNeighbor(OctreeNode fineNode, OctreeNode coarseNode, byte direction, TriangleVertex[] vertices)
          Called from IsoSurface.findARoctreeNodes()
private  int searchTriangle(Triangle triangle, TriangleVertex newVertex)
          This is called from IsoSurface.compareVertices()
 void setInterpolator(Interpolator i)
           
private  void setIsoSurfaceAdaptive(IsoSurfaceAdaptive newSurface)
           
 void setIsoValue(float newVal)
           
 void setMarchingCubes(MarchingCubes mc)
           
private  void setNumCubes()
          Set the number of cubes containing this isosurface.
private  void setTriangleVertexList(TriangleVertexList tvl)
           
private  int sharedVertex(OctreeNode octreeNode, TriangleVertex triangleVertex)
          Note: IsoSurface.sharedVertex() is called from IsoSurface.computeTriangle()
private  int updateTriangleVertexList(OctreeNode node, TriangleVertex newVertex)
          This method updates the TriangleVertexList object.
 
Methods inherited from class java.util.Vector
add, add, addAll, addAll, addElement, capacity, clear, clone, contains, containsAll, copyInto, elementAt, elements, ensureCapacity, ensureCapacityHelper, equals, firstElement, get, hashCode, indexOf, indexOf, insertElementAt, isEmpty, lastElement, lastIndexOf, lastIndexOf, readObject, remove, remove, removeAll, removeAllElements, removeElement, removeElementAt, removeRange, retainAll, set, setElementAt, setSize, size, subList, toArray, toArray, toString, trimToSize, writeObject
 
Methods inherited from class java.util.AbstractList
iterator, listIterator, listIterator
 
Methods inherited from class java.lang.Object
, finalize, getClass, notify, notifyAll, registerNatives, wait, wait, wait
 
Methods inherited from interface java.util.List
iterator, listIterator, listIterator
 

Field Detail

isoValue

private float isoValue
number of octree nodes/cubes in isosurface

interpolator

private Interpolator interpolator

triangleVertexList

private TriangleVertexList triangleVertexList

numCubes

private int numCubes
number of octree nodes/cubes in isosurface

MC

private MarchingCubes MC
passed in order to use the generateTopologicalIndex() and getEdges() methods from the compareEdges() method

isoSurfaceAdaptive

private IsoSurfaceAdaptive isoSurfaceAdaptive
Constructor Detail

IsoSurface

public IsoSurface(float isoVal,
                  MarchingCubes mc)
constructor
Method Detail

getNumCubes

private int getNumCubes()
Returns:
the number of cubes containing this isosurface

setNumCubes

private void setNumCubes()
Set the number of cubes containing this isosurface.

getMarchingCubes

public MarchingCubes getMarchingCubes()
Returns:
-this IsoSurface's MarchingCubes object

setMarchingCubes

public void setMarchingCubes(MarchingCubes mc)
Parameters:
mc - this IsoSurface object's MarchingCubes object

getInterpolator

public Interpolator getInterpolator()
Returns:
this surface's interpolator

setInterpolator

public void setInterpolator(Interpolator i)
Parameters:
this - surface's interpolator

getIsoSurfaceAdaptive

private IsoSurfaceAdaptive getIsoSurfaceAdaptive()
Returns:
the adaptive resolution portion of the isosurface

setIsoSurfaceAdaptive

private void setIsoSurfaceAdaptive(IsoSurfaceAdaptive newSurface)
Parameters:
newSurface - the adaptive resolution portion of the isosurface

addSecondPassNode

private boolean addSecondPassNode(OctreeNode coarseNode,
                                  boolean firstPass)
Parameters:
coarseNode - one to add to the secondPassList
firstPass - is TRUE if we are performing MC on the first pass through the octree
Returns:
TRUE if it was actually added to the list, FALSE if it was already on the list.

processAdaptiveSurface

public void processAdaptiveSurface()
This is called from MarchingCubes.execute() (at the end)

getIsoValue

public float getIsoValue()
Returns:
-the isosurface value

setIsoValue

public void setIsoValue(float newVal)
Parameters:
isoValue - this IsoSurface object's isovalue

getVertexList

public TriangleVertexList getVertexList()
Returns:
the list of unique TriangleVertex objects that make up this IsoSurface

setTriangleVertexList

private void setTriangleVertexList(TriangleVertexList tvl)
Parameters:
the - list of unique TriangleVertex objects that make up this IsoSurface

computeTriangles

public void computeTriangles(OctreeNode node,
                             byte[] edges,
                             boolean firstPass)
The computeTriangles() method creates a new triangle for each set of 3 edge intersections in the cube.

Parameters:
node - the octree node (and bounding cube) that contains the triangles
edges - the list of edge intersections
firstPass - is TRUE if we are to check for AR octree nodes

computeTriangle

private void computeTriangle(OctreeNode node,
                             byte[] edges,
                             byte[] uniqueEdges,
                             boolean firstPass)
Here's a edge to vertex pair mapping. See page 233 Figure 8-11 of the Visualization Toolkit (First Edition) and the vtkMarchingCubes.cc source code for inspiration behind this mapping. Also looking in MarchingCubes.cc of the VTK source code for the list of edges.
Note the orientation of the x,y,z axis.

             P7_____________P6   This is the cube representation
             /|            /|    used to write the computeTriangle()
            / |           / |    method.  It is the same as the VTK's.
         P4/___________P5/  |    
          |   |         |   |    
   z      |   |         |   |    
   ^   y  |   |         |   |
   |  /   | P3|_________|___|P2
   | /    |  /          |  /
   |/     | /           | /
    --->  |/____________|/
       x P0             P1
 
[Note: there's room for optimization in this procedure]

Parameters:
octreeNode - the node (and bounding cube) that contains the triangles
edges - the list of edge intersections
uniqueEdges - a list of edges that have already been processed
firstPass - is TRUE if we performing MC on the first pass through the octree (not on the 2nd pass list)

addTriangleToSurface

public Triangle addTriangleToSurface(OctreeNode node,
                                     int[] listIndices)
This is called from IsoSurface.computeTriangle() and OctreeARnode.assembleTriangleFan()

Parameters:
node - the octree node that will host these triangle vertices
listIndices - 3 triangle vertex list indices determine where in the triangle vertex list these indices reside
Returns:
the triangle object that was added to the surface

addVerticesToVertexList

public int[] addVerticesToVertexList(OctreeNode node,
                                     TriangleVertex[] vertices)
This is called from IsoSurface.computeTriangle() and OctreeARnode.assembleTriangleFan()

Parameters:
node - the octree node that will host these triangle vertices We pass this octree node here to so it can search itself and it's neighbors for a shared vertex (and not the whole triangle vertex list)
vertices - a set of 3 triangle vertices to add to the triangle vertex list
Returns:
3 triangle vertex list indices determine where in the triangle vertex list these indices reside

isNew

private boolean isNew(byte[] uniqueEdges,
                      byte edge)
Parameters:
uniqueEdges - a list of unique cube edges
edge - a single cube edge
Returns:
TRUE if the given edge is not already in the list of unique cube edges i.e. IF it is a "new" edge

findARoctreeNodes

private boolean findARoctreeNodes(OctreeNode octreeNode,
                                  byte[] directions,
                                  TriangleVertex[] vertices,
                                  boolean firstPass)
Note: IsoSurface.findARoctreeNodes() is called from IsoSurface.computeTriangle()

Basic algorithm:

 

Parameters:
octreeNode - the octree node whose neighbors are searched
edge - the directions in which to search of an AR node
vertices - a set of 3 new triangle vertices that belong to the given octree node
firstPass - is TRUE if we performing MC on the first pass throught the octree
Returns:
TRUE -IF a neighboring adaptive resolution octree node was found

processCoarserNeighbor

private boolean processCoarserNeighbor(OctreeNode fineNode,
                                       OctreeNode coarseNode,
                                       byte direction,
                                       TriangleVertex[] vertices)
Called from IsoSurface.findARoctreeNodes()

Again we have to check for shared edge vertices and facial vertices on the coarser neighbor. We put the coarser neighbor on the AR isosurface if we find any shared vertices on either the edges or the face of the neighbor independent of any vertices generated by the coarse neighbor.

This is because we cannot predict what the final state of coarser neighbor will be until all of its finer resolution neighbors have been processed.

Parameters:
fineNode - the finer resolution octree node
coarseNode - the coarser resolution neighboring octree node
direction - the direction FROM the fine node TO the coarse node.
vertices - a set of 3 new triangle vertices that may be be shared with the coarse neighbor node
Returns:
TRUE if the fineVertex was found to be shared with the given coarse neighbor

addARverticesToNeighbor

private void addARverticesToNeighbor(OctreeNode coarseNode,
                                     SharedVertex[] vertices)
This method is called from IsoSurface.processCoarserNeighbor()

Parameters:
coarseNode - the coarser resolution octree node that we'll add AR triangle vertices too
vertices - a possible set of 3 shared triangle vertices that might be added to the given octree node

addSingletons

private void addSingletons(OctreeNode coarseNode,
                           SharedVertex[] vertices,
                           boolean[] addSingleton)
This method is called from IsoSurface.addARverticesToNeighbor()

Parameters:
coarseNode - the coarser resolution octree node that we'll add AR triangle vertices too
vertices - a possible set of 3 shared triangle vertices that might be added to the given octree node
addSingleton - indicates shared trianlge vertices that are not part of an edge but still are on either a face or an edge of their neighbor

sharedVertex

private int sharedVertex(OctreeNode octreeNode,
                         TriangleVertex triangleVertex)
Note: IsoSurface.sharedVertex() is called from IsoSurface.computeTriangle()

sharedVertex() looks at the given node's neighbors to see if the given vertex has already been computed in an effort to find a shared vertex.

Since we are traversing the cubes in order 0,1,2,...7 we search the 3 neighbors whose triangles have already been computed.

Parameters:
octreeNode - the octree node whose neighbors are searched
triangleVertex - the vertex that may be shared
Returns:
vertexIndex -IF a matching vertex is found, the matching vertex's index into the triangleVertexList is returned.

inspectNeighbors

private int inspectNeighbors(byte[] directions,
                             OctreeNode octreeNode,
                             TriangleVertex triangleVertex)
Parameters:
directions - an array of directions in which to search for a face neighbor
octreeNode - the octree node whose neighbors are searched
triangleVertex - the vertex that may be shared
Returns:
vertexIndex -IF a matching vertex is found, the matching vertex's index into the triangleVertexList is returned.

updateTriangleVertexList

private int updateTriangleVertexList(OctreeNode node,
                                     TriangleVertex newVertex)
This method updates the TriangleVertexList object. The given octree node looks at its neighbors to see if they have already computed this vertex.
 IF one of the neighbors already has NOT THEN
    add this new vertex to the TriangleVertexList
 

Parameters:
node - the OctreeNode with the new TriangleVertex
newVertex - the new (possibly shared) TriangleVertex
Returns:
vertexListIndex -the index into the TriangleVertexList at which the given TriangleList can be located

computeVertex

private TriangleVertex computeVertex(OctreeNode node,
                                     byte edge)
This method is called from IsoSurface.computeTriangle() .

Note: the way we pass the vertices makes the interpolator's job easier. We'll always pass the vertex with the lesser coordinate value (along the axis of interpolation) first.

Parameters:
node - an octree node and hence bounding cube that contains the triangles
edge - an edge intersection
Returns:
either an IsoX, IsoY, or IsoZ vertex

compareVertices

private int compareVertices(OctreeNode octreeNode,
                            TriangleVertex newVertex)
This method searches the given octree node's list of triangle vertices to see if one is the same as the given triangle vertex. We're searching for shared vertices.

Parameters:
octreeNode - the octree node whose triangles are searched
triangleVertex - the vertex that may be shared
Returns:
vertexIndex -IF a matching vertex is found, the matching vertex's index into the triangleVertexList is returned

searchTriangle

private int searchTriangle(Triangle triangle,
                           TriangleVertex newVertex)
This is called from IsoSurface.compareVertices()

Parameters:
triangle - the triangle we are searching for a matching vertex
vertex - the vertex whose match we are searching for

addTriangle

public void addTriangle(Triangle triangle)
addTriangle() adds a triangle onto the IsoSurface.

Parameters:
triangle - a new triangle

addNode

public void addNode(OctreeNode node)
addNode() adds a node, that has a triangle list, onto the IsoSurface.
Note: do not add nodes onto the list if they are already there

Parameters:
node - an octreeNode

getTriangle

public Triangle getTriangle(int n)
getTriangle() returns triangle, n , in the IsoSurface.

Parameters:
n - triangle number
canvas - the painting canvas
Returns:
triangle -IsoSurface triangle n

getActualVisADcoords

public float[] getActualVisADcoords(int dimension)
"Actual" means get each unique vertex out of the vertex list i.e. no redundant vertices.

Note, there may be some invalid vertices in the triangleVertexList This is a result of "removing" vertices from the list by setting their values to -1. The reason for this is when we want to remove an OctreeNode's triangles from the list, however, since triangle is simply a set of three integer indexes into the list, we cannot use the Vector.removeElement() method because the vector is resized causing an average of half of the integer index values to be wrong. Therefore we just set the vertices we want to remove to -1, and exclude them from the Gridded3DMRSet object's TriangleStripArray .

This method is called from Gridded3DMRSet.make_isoSurface()

Parameters:
dimension - the dimension (x,y,z) of the coordinate values
Returns:
float[] -all the unique x, y, or z coordinate values

getError

float[] getError()
This hastily written method will return the error values associated with the surface points -PJR

getActualNumVertices

public int getActualNumVertices()
This method is called from Gridded3DMRSet.makeIsoSurface()

Parameters:
dimension - the dimension (x,y,z) of the coordinate values
Returns:
float[] -all the x, y, or z coordinate values along the

getNumPolygons

public int getNumPolygons()

print

public void print()
Used for testing

IsoSurface Rendering of an AR Representation