A set of contour bands are drawn on a 2D slice through a 3D field.
The field input must be a slice through a uniform or irregular 3D grid.
If the field is uniform, the plane of the output contour geometry
will have its correct position in 3D space.
The data values for the contours are taken from the 'levels' input field.
If this input is not present, then the range of the data field input is
divided equally to generate N contour levels. There are always at least
two contour levels, giving at least one bounded band. If the levels are
generated locally then the first and last contour levels are always at
the minimum and maximum data values, so the open bands above and
below the data range will not be seen. If the levels are generated in
an INTERVALS FIELD module, the local 'N' control parameter is removed.
If the colour map input is not connected, the contour bands will be
given a default greyscale spectrum. If a colour map is present,
the field data range is mapped to the colour value range. If the
colour value range has been set using the 'color range' module the
ranges will match exactly: the band below the minimum level is given
the first colour index; and the band above the maximum level is given
the last colour index. In general, these underflow/overflow bands will
not be visible on the slice. If the colour value range is completely
within the field data range, there may be duplicated colours at the
bottom and top of the range. If the field data range is completely
within the colour value range, the contour colours will be a restricted
subset of the full gamut of colours.
The discretized colour map used for the bands is made available as an
output colormap. This can be displayed using the FIELD LEGEND module.
The underflow/overflow band colours are displayed at the ends of this
spectrum even though there may not be any bands with these colours in
the slice. Having such excluded endpoints makes it easy to see when the
data has overrun the available spectrum. The colormap output can have
black lines inserted at the band boundaries to simulate the effect of
the ISOLINE SLICE module. These lines are controlled using the
'Colourmap Boundary' boolean parameter.
There is a bug in the standard DOWNSIZE module.
The problem arises when using DOWNSIZE for uniform fields when the
downsize value is not an exact factor of all the (dimension-1) values
in X, Y and Z. In this case the output should not fill the input extents,
there will be a gap for the 'remainder', but the standard module fills the
extents. The result is that spatial positions within field slices
will be slightly wrong. This will be most noticeable when two contour
surfaces intersect - the bands will not match exactly. A fixed version
of the DOWNSIZE module is supplied with the contouring suite, it's
module name is 'Downsize', the upper case initial is used to distinguish
it from the standard version.
*************************************************************
* THE NEW DOWNSIZE MODULE MUST BE USED WITH UNIFORM FIELDS *
* FOR CORRECT SPATIAL OUTPUT FROM CONTOURING MODULES *
*************************************************************
The "Smooth Surface" mode will optionally create interpolated surface
normals, so Gouraud shading will work correctly.
The default is "flat" or no shading.
[Update:] The "Leave Holes" mode checks the values present at all
four corners of each patch and will only draw the patch if
they are all within the input colormap range. This can be used
to set certain vertices in the mesh to large out-of-range values
to mark invalid data, so that the cells that reference this node
will "drop out" rather than screw up the interpolation.
Enabling 'Outline' modes in the Object menu of the Geometry Viewer
will produce contour lines and the cell boundaries in wireframe.
Each edge will be represented by two lines, so there may be some
rasterizing artifacts, including 'ropiness' with anti-aliasing.
METHOD
The contouring is performed independently for every cell.
The method is a hybrid: the majority of situations can be
handled by walking round the cell interpolating vertices and rendering
the resulting polygon; but for saddle situations there needs to be
a decomposition within the cell. The refinement is accomplished using
a 2D variation on the 'marching cubes' algorithm: a look-up table
is maintained for all possible configurations of cells; an index is
calculated for each cell-band combination; the central value (cell
average) is used in conjunction with the index to read an entry from
the table. In this case the entry will be a pointer list to rearrange
the interpolated vertices into two polygons. This hybrid method is well
optimized because only a tiny fraction of cases will progress to the
final stages of refinement.
Here is a summary of the algorithm :
read or calculate contour levels
for every cell
for each edge
either copy a vertex point or interpolate along the edge
add the new point to the points list
tag the contour lists to which the point contributes
end edges
for each contour band
get the contour list of tagged points
if simple polygon
draw the simple polygon
else
calculate index
calculate central (average) cell value
if index/average corresponds to simple polygon
draw the simple polygon
else saddle
read the pointer array for this index/average (look-up table)
rearrange the points and draw two polygons
end if
end if
end bands
end cells
Only the simplest interpolations are performed, i.e. linear
fraction along edges, the band has no vertices inside the cell.
The saddle points are resolved by calculating the average value
at the centre of the cell and using this to determine whether the index
needs to be applied. In general there will be 81 cases for the cell
vertices. Of these, 14 are saddle conditions which need the central
value calculating. Usually each of the 14 cases will have two possible
outcomes, one requiring the output to be subdivided into two polygons,
the other just reverts to a simple polygon. The exception is the
8-sided output, which can be subdivided into two polygons in two
different ways. The fourteen saddle cases are shown below, the cell
vertices and the centre of the cell are marked with a 'x' if their
value is above the band level, '@' if their value lies within the band,
and a 'o' if their value is below the band.
6-sided (with rotations, 2 examples of each)
o @ o ---@ o ---@
\ | / |
? ---> |\ o \| OR / @ / central x impossible
| \ | /
@ o @-- o @--- o
x @ x ---@ x ---@
\ | / |
? ---> |\ x \| OR / @ / central o impossible
| \ | /
@ x @-- x @--- x
7-sided (with rotations, 4 examples of each)
o x o -- x o --- x
\\ / \
? ---> |\ o \| OR | @ | central x like @
| \ | /
@ o @-- o @---- o
x o x -- o x --- o
\\ / \
? ---> |\ x \| OR | @ | central x like o
| \ | /
@ x @-- x @---- x
8-sided (with rotations, 2 examples)
x o x -- o x -- o x --- o
\\ // / \
? ---> |\ x \| OR |/ o /| OR | @ |
\\ // \ /
o x o -- x o -- x o --- x
Processing per-cell means that values are interpolated along each edge
twice - once for each cell to which the edge belongs - but intermediate
values only have to be stored for each cell. So the algorithm could be
speeded up by a factor ~2 by retaining the interpolated points for the
previous and current rows. After the first row, and the first cell in
each subsequent row, only 2 edges have to processed per-cell, rather
than 4 with the existing algorithm. The pointer tables are already
doubly dereferenced, so retaining data will add another level of
indirection. This will complicate the data handling, but pay-off with a
significant performance improvement.
The composite algorithm is original and unpublished by this author,
it is very simple and must have been published somewhere before.
The marching cubes idea (index and look-up table) was used without
referring to any particular paper.
BUGS & 'FEATURES'
The algorithm used to draw the polygonal bands assumes that the patch is
planar. The rendering of non-planar polygons is achieved by converting
the POLYHEDRON surface to a POLYTRI mesh. This means that AVS will take
care of the triangulation of non-planar quadrilaterals, they will appear
as multi-sided areas composed of triangular facets.
FUTURE WORK
A wish-list would include:
- global interpolation to get the x2 speed-up mentioned above
- extend to rectilinear field types
- integrate contour line output in the 'outline' wireframe
description, so it could be selected using the Object mode
menu, rather than using a separate module. This would also
have the advantage that most hardware renderers would automatically
offset the contour lines in Z, so that surface and lines don't
clash in the Z-buffer