.. 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.