.. Higher-Order Tensor Glyphs in Teem documentation master file, created by
sphinx-quickstart on Thu Jul 1 15:45:28 2010.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
.. highlight:: c
.. _Teem: http://teem.sf.net/
Higher-Order Tensor Glyphs in Teem
==================================
A significant part of the C code written for our paper [SK10]_ is
available in the open source library Teem_. On this page, we will
explain how you can integrate this portable and efficient code
directly into your own favorite visualization framework.
The relevant modules are called limn (OpenGL-oriented geometry
processing), tijk (higher-order tensor algebra), and elf (the actual
glyph implementation). Tijk and elf are still flagged as
"experimental", so make sure to get the latest version from the SVN
and enable experimental libraries when building Teem, as described in
my `quick introduction `__. In your application,
you'll need to
::
#include
First, let's tesselate a unit sphere by repeated subdivision of an
icosahedron. Three levels of subdivision produce 642 vertices and are
sufficient for nice-looking glyphs.
::
unsigned int level=3;
unsigned int infoBitFlag=(1<num],res[type->num];
/* convert even-order spherical harmonics to higher-order tensor */
tijk_esh_to_3d_sym_f(ten, esh, 4);
/* create positive approximation of the tensor */
tijk_refine_rankk_parm *parm=tijk_refine_rankk_parm_new();
parm->pos=1;
tijk_approx_rankk_3d_f(NULL, NULL, res, ten, type, 6, parm);
parm=tijk_refine_rankk_parm_nix(parm);
tijk_sub_f(ten,ten,res,type);
Tijk currently implements symmetric 2nd-order, 4th-order, and
6th-order 3D tensors. Orders higher than six might be added in the
future.
Glyph generation transforms (and thus overwrites) the unit sphere that
is provided as an input. To avoid having to re-create the sphere from
scratch for every glyph, we work with a copy:
::
const char normalize=0;
limnPolyData *glyph = limnPolyDataNew();
limnPolyDataCopy(glyph, sphere);
float radius=elfGlyphHOME(glyph, 1, ten, type, NULL, normalize);
/* at the end of your program: */
glyph=limnPolyDataNix(glyph);
The computed radius specifies a bounding sphere around the glyph and
can be used to cull glyphs that fall outside the viewport. If you want
your surface normals to be unit-length, simply set normalize=1. In my
own code, normalization is done by the vertex shader (during
rendering). To generate the traditional polar plot, simply use
elfGlyphPolar() instead of elfGlyphHOME().
So far, your glyph will have the traditional per-vertex, rainbow-like
XYZ-RGB coloring. If you prefer the per-peak coloring described in our
paper, you will first need to extract the direct neighbors of each
mesh vertex:
::
int *neighbors;
unsigned int nbstride;
limnPolyDataNeighborArray(&neighbors, &nbstride, glyph);
Once you have the neighbors (which will be the same for all glyphs, so
they only need to be computed once), simply call:
::
elfColorGlyphMaxima(glyph, 1, neighbors, nbstride, ten, type, 1, 0.8);
That's it. If you look at the definition of limnPolyData in
teem/limn.h, it should be obvious how to render the result via
standard OpenGL calls (I'm using glDrawElements, combined with vertex
buffer objects). You may want to look at the documentation of the
individual functions to tweak parameters or do proper error checking.
All above-mentioned functions are thread-safe, so you
can have all your CPU cores work on creating and coloring glyph
geometry in parallel.
References
----------
.. [DAFD07] Maxime Descoteaux, Elaine Angelino, Shaun Fitzgibbons,
Rachid Deriche. Regularized, Fast, and Robust Analytical Q-Ball
Imaging. Magnetic Resonance in Medicine 28:497-510, 2007.
.. [SK10] Thomas Schultz and Gordon Kindlmann. A Maximum Enhancing
Higher-Order Tensor Glyph. Computer Graphics Forum (Proc. EuroVis)
29(3):1143-1152, 2010.