30 #include <osg/Geometry>
31 #include <osg/LightModel>
34 #include "WMTeemGlyphs.h"
35 #include "WMTeemGlyphs.xpm"
36 #include "core/common/WAssert.h"
37 #include "core/common/WConditionOneShot.h"
38 #include "core/common/WLimits.h"
39 #include "core/common/WPropertyHelper.h"
40 #include "core/common/WStringUtils.h"
41 #include "core/common/WThreadedFunction.h"
42 #include "core/kernel/WKernel.h"
58 void estimateNormalsAntipodal( limnPolyData *glyph,
const char normalize )
60 unsigned int faceno = glyph->indxNum/3;
61 unsigned int *faces = glyph->indx;
63 memset( glyph->norm, 0,
sizeof(
float )*3*glyph->xyzwNum );
64 for( f = 0; f < faceno/2; f++ )
69 ELL_3V_SUB( diff1, glyph->xyzw+4*faces[3*f+1],
70 glyph->xyzw+4*faces[3*f] );
71 ELL_3V_SUB( diff2, glyph->xyzw+4*faces[3*f+2],
72 glyph->xyzw+4*faces[3*f] );
73 ELL_3V_CROSS( cross, diff1, diff2 );
74 ELL_3V_INCR( glyph->norm+3*faces[3*f], cross );
75 ELL_3V_INCR( glyph->norm+3*faces[3*f+1], cross );
76 ELL_3V_INCR( glyph->norm+3*faces[3*f+2], cross );
78 if( faces[3*f]%2 == 0 )
80 ELL_3V_SUB( glyph->norm+3*faces[3*f]+3, glyph->norm+3*faces[3*f]+3, cross );
84 ELL_3V_SUB( glyph->norm+3*faces[3*f]-3, glyph->norm+3*faces[3*f]-3, cross );
86 if( faces[3*f+1]%2 == 0 )
88 ELL_3V_SUB( glyph->norm+3*faces[3*f+1]+3, glyph->norm+3*faces[3*f+1]+3, cross );
92 ELL_3V_SUB( glyph->norm+3*faces[3*f+1]-3, glyph->norm+3*faces[3*f+1]-3, cross );
94 if( faces[3*f+2]%2 == 0 )
96 ELL_3V_SUB( glyph->norm+3*faces[3*f+2]+3, glyph->norm+3*faces[3*f+2]+3, cross );
100 ELL_3V_SUB( glyph->norm+3*faces[3*f+2]-3, glyph->norm+3*faces[3*f+2]-3, cross );
107 for( i = 0; i < glyph->normNum; i++ )
109 ELL_3V_NORM_TT( glyph->norm + 3*i,
float, glyph->norm + 3*i, len );
121 return std::shared_ptr< WModule >(
new WMTeemGlyphs() );
126 return teemGlyphs_xpm;
132 return "Teem Glyphs";
137 return "Higher-Order Tensor Glyphs as described at http://www.ci.uchicago.edu/~schultz/sphinx/home-glyph.html";
142 m_input = std::shared_ptr< WModuleInputData < WDataSetSphericalHarmonics > >(
147 "inGFA",
"Generalized fractional anisotropy." )
165 "Which slice will be shown?",
174 m_orders->addItem(
"2",
"Order 2" );
175 m_orders->addItem(
"4",
"Order 4" );
176 m_orders->addItem(
"6",
"Order 6" );
179 "Order of the displayed spherical harmonics."
180 " If actual order is higer, the additional coefficients are ignored.",
186 " anisotropy (GFA) threshold"
187 " (if GFA data is present at input connector).",
203 "Determines the glyph resolution. Subdivision level of"
204 " icosahadra use as sphere approximations.",
212 " Do <b>not</b> use with \"Hide negative lobes\"!",
219 " Do <b>not</b> use with \"Min-max normalization\"!",
243 if( !
m_input->getData().get() )
246 debugLog() <<
"Waiting for data ...";
252 bool dataChanged =
false;
260 std::shared_ptr< WGridRegular3D > gridReg = std::dynamic_pointer_cast< WGridRegular3D >(
m_input->getData().get()->getGrid() );
279 std::shared_ptr< WDataSetScalar > gfa =
m_inputGFA->getData();
320 debugLog() <<
"Rendering Slice " << sliceId;
321 std::shared_ptr< WProgress > progress;
322 progress = std::shared_ptr< WProgress >(
new WProgress(
"Glyph Generation", 2 ) );
327 string_utils::fromString< float >(
m_orders->getSelector(
m_orderProp->get(
true ).getItemIndexOfSelected( 0 ) ) .at( 0 )->getName() );
342 std::shared_ptr< GlyphGeneration > generator;
343 generator = std::shared_ptr< GlyphGeneration >(
345 std::dynamic_pointer_cast< WDataSetScalar >(
m_inputGFA->getData() ),
358 generatorThreaded.
run();
359 generatorThreaded.
wait();
367 osg::ref_ptr< osg::Geode > glyphsGeode = generator->getGraphics();
412 for(
size_t vertID = 0; vertID < glyph->xyzwNum; ++vertID )
414 WPosition pos( glyph->xyzw[nbVertCoords*vertID], glyph->xyzw[nbVertCoords*vertID+1], glyph->xyzw[nbVertCoords*vertID+2] );
415 double norm = length( pos );
426 double dist = max - min;
430 WAssert( dist > 0.0,
"Max has to be larger than min." );
432 for(
size_t i = 0; i < glyph->xyzwNum; ++i )
434 size_t coordIdBase = nbVertCoords * i;
435 WPosition pos( glyph->xyzw[coordIdBase], glyph->xyzw[coordIdBase+1], glyph->xyzw[coordIdBase+2] );
436 double norm = length( pos );
437 const double epsilon = 1e-9;
440 newPos = ( ( ( norm - min ) / dist ) + epsilon ) * pos / norm;
441 glyph->xyzw[coordIdBase] = newPos[0];
442 glyph->xyzw[coordIdBase+1] = newPos[1];
443 glyph->xyzw[coordIdBase+2] = newPos[2];
450 std::shared_ptr< WDataSetScalar > dataGFA,
452 const size_t& sliceId,
454 const size_t& subdivisionLevel,
455 const size_t& modulo,
456 const size_t& sliceType,
457 const bool& usePolar,
459 const bool& useNormalization,
460 const bool& useRadiusNormalization,
461 const bool& hideNegativeLobes ) :
463 m_dataGFA( dataGFA ),
464 m_grid( std::dynamic_pointer_cast<
WGridRegular3D >( dataSet->getGrid() ) ),
465 m_thresholdGFA( thresholdGFA ),
467 m_sliceType( sliceType ),
468 m_subdivisionLevel( subdivisionLevel ),
470 m_usePolar( usePolar ),
472 m_useNormalization( useNormalization ),
473 m_useRadiusNormalization( useRadiusNormalization ),
474 m_hideNegativeLobes( hideNegativeLobes )
507 unsigned int infoBitFlag = ( 1 << limnPolyDataInfoNorm ) | ( 1 << limnPolyDataInfoRGBA );
510 limnPolyDataIcoSphere(
m_sphere, infoBitFlag, level );
513 m_vertArray = osg::ref_ptr< osg::Vec3Array >(
new osg::Vec3Array() );
514 m_normals = osg::ref_ptr< osg::Vec3Array >(
new osg::Vec3Array() );
515 m_colors = osg::ref_ptr< osg::Vec4Array >(
new osg::Vec4Array() );
518 m_colors->resize( nbVerts * nbGlyphs, osg::Vec4( 0, 0, 0, 1.0 ) );
520 m_glyphElements = osg::ref_ptr< osg::DrawElementsUInt >(
new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES ) );
527 m_sphere = limnPolyDataNix( m_sphere );
532 const size_t nbVertCoords = 4;
533 limnPolyData *localSphere = limnPolyDataNew();
534 limnPolyDataCopy( localSphere, m_sphere );
542 WAssert( m_sphere->xyzwNum == m_sphere->normNum,
"Wrong size of arrays." );
543 WAssert( m_sphere->xyzwNum == m_sphere->rgbaNum,
"Wrong size of arrays." );
544 size_t nbVerts = m_sphere->xyzwNum;
546 const tijk_type *type = 0;
547 const tijk_type *typeOrder2 = tijk_2o3d_sym;
548 const tijk_type *typeOrder4 = tijk_4o3d_sym;
549 const tijk_type *typeOrder6 = tijk_6o3d_sym;
552 float* ten =
new float[ typeOrder6->num ];
553 float* res =
new float[ typeOrder6->num ];
554 float* esh =
new float[ typeOrder6->num ];
557 size_t chunkSize = m_nA / ( numThreads - 1 );
558 size_t first =
id * chunkSize;
560 size_t lastPlusOne = (
id + 1 ) * chunkSize;
562 if(
id == numThreads - 1 )
567 std::stringstream ss;
568 ss <<
id <<
"/" << numThreads <<
" (" << first <<
" ... " << lastPlusOne - 1 <<
")[" << chunkSize <<
"/" << m_nA <<
"]" << std::endl;
571 for(
size_t aId = first; aId < lastPlusOne; ++aId )
573 for(
size_t bId = 0; bId < m_nB; ++bId )
575 if( ( aId % m_modulo != 0) || ( bId % m_modulo != 0 ) )
579 size_t glyphId = ( aId / m_modulo ) * ( ( m_nB + ( m_modulo - 1 ) ) / m_modulo ) + ( bId / m_modulo );
581 size_t vertsUpToCurrentIteration = glyphId * nbVerts;
582 size_t idsUpToCurrentIteration = glyphId * m_sphere->indxNum;
585 switch( m_sliceType )
588 posId = m_sliceId + aId * m_nX + bId * m_nX * m_nY;
591 posId = aId + m_sliceId * m_nX + bId * m_nX * m_nY;
594 posId = aId + bId * m_nX + m_sliceId * m_nX * m_nY;
603 for(
unsigned int vertId = 0; vertId < localSphere->indxNum; ++vertId )
605 ( *m_glyphElements )[idsUpToCurrentIteration+vertId] = ( vertsUpToCurrentIteration + localSphere->indx[vertId] );
609 if( m_dataGFA && std::static_pointer_cast< WDataSetSingle >( m_dataGFA )->getValueAt( posId ) < m_thresholdGFA )
615 int countOfCoeffsToUse = 0;
619 countOfCoeffsToUse = 6;
622 countOfCoeffsToUse = 15;
625 countOfCoeffsToUse = 28;
628 WAssert(
false,
"order above 6 not supported yet." );
630 countOfCoeffsToUse = std::min(
static_cast< int >( coeffs.
size() ), countOfCoeffsToUse );
634 switch( countOfCoeffsToUse )
649 WAssert(
false,
"order above 6 not supported yet." );
652 for(
int coeffId = 0; coeffId < countOfCoeffsToUse; ++coeffId )
654 esh[ coeffId ] = coeffs[ coeffId ];
661 for(
int l = 0; l <= useOrder; l += 2 )
663 for(
int m = -l; m <= l; ++m )
665 if( m < 0 && ( ( -m ) % 2 == 1 ) )
669 else if( m > 0 && ( m % 2 == 0 ) )
678 tijk_esh_to_3d_sym_f( ten, esh, useOrder );
680 const char normalize = 0;
682 limnPolyData *glyph = limnPolyDataNew();
683 limnPolyDataCopy( glyph, localSphere );
689 radius = elfGlyphPolar( glyph, 1, ten, type, &isdef, m_hideNegativeLobes, normalize, NULL, NULL );
694 tijk_refine_rankk_parm *parm = tijk_refine_rankk_parm_new();
696 int ret = tijk_approx_rankk_3d_f( NULL, NULL, res, ten, type, 6, parm );
697 WAssert( ret == 0,
"Error condition in call to tijk_approx_rankk_3d_f." );
698 parm = tijk_refine_rankk_parm_nix( parm );
699 tijk_sub_f( ten, ten, res, type );
701 radius = elfGlyphHOME( glyph, 1, ten, type, NULL, normalize );
708 float scale = m_scale;
710 if( m_useNormalization )
712 minMaxNormalization( glyph, nbVertCoords );
713 if( !m_useRadiusNormalization )
715 scale = m_scale * radius;
720 if( m_useRadiusNormalization )
724 scale = m_scale / radius;
732 estimateNormalsAntipodal( glyph, normalize );
734 WPosition glyphPos = m_grid->getPosition( posId );
737 for(
unsigned int vertId = 0; vertId < glyph->xyzwNum; ++vertId )
739 size_t globalVertexId = vertsUpToCurrentIteration + vertId;
742 ( *m_vertArray )[globalVertexId][0] = glyph->xyzw[nbVertCoords*vertId ] * scale + glyphPos[0];
743 ( *m_vertArray )[globalVertexId][1] = glyph->xyzw[nbVertCoords*vertId+1] * scale + glyphPos[1];
744 ( *m_vertArray )[globalVertexId][2] = glyph->xyzw[nbVertCoords*vertId+2] * scale + glyphPos[2];
748 ( *m_normals )[globalVertexId][0] = glyph->norm[3*vertId];
749 ( *m_normals )[globalVertexId][1] = glyph->norm[3*vertId+1];
750 ( *m_normals )[globalVertexId][2] = glyph->norm[3*vertId+2];
751 ( *m_normals )[globalVertexId].normalize();
755 const size_t nbColCoords = 4;
756 ( *m_colors )[globalVertexId][0] = glyph->rgba[nbColCoords*vertId] / 255.0;
757 ( *m_colors )[globalVertexId][1] = glyph->rgba[nbColCoords*vertId+1] / 255.0;
758 ( *m_colors )[globalVertexId][2] = glyph->rgba[nbColCoords*vertId+2] / 255.0;
759 ( *m_colors )[globalVertexId][3] = glyph->rgba[nbColCoords*vertId+3] / 255.0;
763 glyph = limnPolyDataNix( glyph );
768 localSphere = limnPolyDataNix( localSphere );
777 osg::ref_ptr< osg::Geometry > glyphGeometry =
new osg::Geometry();
778 glyphGeometry->setVertexArray( m_vertArray );
779 glyphGeometry->addPrimitiveSet( m_glyphElements );
780 glyphGeometry->setNormalArray( m_normals );
781 glyphGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
782 glyphGeometry->setColorArray( m_colors );
783 glyphGeometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
786 osg::ref_ptr< osg::Geode > glyphsGeode;
787 glyphsGeode = osg::ref_ptr< osg::Geode >(
new osg::Geode );
788 glyphsGeode->setName(
"teem glyphs" );
789 osg::StateSet* state = glyphsGeode->getOrCreateStateSet();
790 state->setMode( GL_BLEND, osg::StateAttribute::ON );
792 glyphsGeode->addDrawable( glyphGeometry );
virtual void wait() const
Wait for the condition.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Class to wrap around the osg Group node and providing a thread safe add/removal mechanism.
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
A grid that has parallelepiped cells which all have the same proportion.
A class containing a list of named items.
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
void addLogMessage(std::string message, std::string source="", LogLevel level=LL_DEBUG)
Appends a log message to the logging queue.
static WLogger * getLogger()
Returns pointer to the currently running logger instance.
This class actually generated the glyph geometry.
~GlyphGeneration()
Destructor freeing the data.
size_t m_sliceId
Stores option from property.
osg::ref_ptr< osg::Vec3Array > m_normals
Normals of the vertices of the glyphs.
size_t m_nB
Internal variable holding the number of glyphs in the second direction of the slice.
size_t m_nY
Number of voxels in y direction.
osg::ref_ptr< osg::DrawElementsUInt > m_glyphElements
Indices of the vertices of the triangles of the glyphs.
size_t m_nZ
Number of voxels in z direction.
osg::ref_ptr< osg::Geode > getGraphics()
Get the geode of the computed glyphs.
limnPolyData * m_sphere
The geometry of the subdivided icosahedron.
osg::ref_ptr< osg::Vec4Array > m_colors
Colors of the vertices of the glyphs.
size_t m_nA
Internal variable holding the number of glyphs in the first direction of the slice.
std::shared_ptr< WGridRegular3D > m_grid
Pointer to the grid of the treated data set.
size_t m_subdivisionLevel
Store option from property.
GlyphGeneration(std::shared_ptr< WDataSetSphericalHarmonics > dataSet, std::shared_ptr< WDataSetScalar > dataGFA, double thresholdGFA, const size_t &sliceId, const size_t &order, const size_t &subdivisionLevel, const size_t &modulo, const size_t &sliceType, const bool &usePolar, const float &scale, const bool &useNormalization, const bool &useRadiusNormalization, const bool &hideNegativeLobes)
Constructor setting the data pointers and the properties from the module.
void minMaxNormalization(limnPolyData *glyph, const size_t &nbVertCoords)
Makes the radii of the glyph be distributed between [0,1].
size_t m_nX
Number of voxels in x direction.
size_t m_modulo
Store option from property.
void operator()(size_t id, size_t numThreads, WBoolFlag &b)
Computes the glyphs.
osg::ref_ptr< osg::Vec3Array > m_vertArray
Vertices of the triangles of the glyphs.
Spherical harmonics glyphs using teem (http://teem.sourceforge.net/).
std::shared_ptr< WCondition > m_exceptionCondition
condition indicating if any exception was thrown.
virtual const std::string getName() const
Gives back the name of this module.
WPropSelection m_sliceOrientationSelectionProp
To choose whether to x, y or z slice.
WPropInt m_subdivisionLevelProp
Property holding information on the subdivision level of the spheres (resolution).
void handleException(WException const &e)
Handle an exception that was thrown by the threaded function in any worker thread.
osg::ref_ptr< WGEGroupNode > m_moduleNode
Pointer to the modules group node.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
std::shared_ptr< WException > m_lastException
The last exception thrown by any worker thread.
std::shared_ptr< WItemSelection > m_orders
A list of the selectable orders.
std::shared_ptr< WModuleInputData< WDataSetSphericalHarmonics > > m_input
An input connector that accepts spherical harmonics datasets.
virtual void connectors()
Initialize the connectors this module is using.
WPropBool m_hideNegativeLobesProp
Indicates whether to hide negativ radius lobes of glyphs.
virtual const std::string getDescription() const
Gives back a description of this module.
std::shared_ptr< WModuleInputData< WDataSetScalar > > m_inputGFA
The input for the GFA.
WPropSelection m_orderProp
Property holding the order of the SH to show.
std::shared_ptr< WItemSelection > m_sliceOrientations
A list of the selectable slice orientations, i.e x, y and z.
virtual void properties()
Initialize the properties for this module.
std::shared_ptr< WCondition > m_recompute
This condition denotes whether we need to recompute the surface.
void activate()
Gets signaled from the properties object when something was changed.
WPropInt m_moduloProp
Property holding information on how many glyphs will be omited between two glyphs (modulo-1).
osg::ref_ptr< WGEShader > m_shader
The shader used for the glyph surfaces.
WPropDouble m_GFAThresholdProp
Property holding the threshold of GFA above which glyphs should be drawn.
WMTeemGlyphs()
Nothing special with this constructor.
WPropDouble m_glyphSizeProp
Property holding the size of the displayed glyphs.
WPropBool m_useRadiusNormalizationProp
Indicates whether to use radius normalization.
boost::mutex m_moduleNodeLock
Lock to prevent concurrent threads trying access m_moduleNode.
void renderSlice(size_t sliceId)
Renders all glyphs for the given slice.
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
WPropBool m_usePolarPlotProp
Property indicating whether to use polar plot instead of HOME glyph.
WPropBool m_useNormalizationProp
Indicates whether to use min max normalization.
virtual void moduleMain()
Entry point after loading the module.
virtual ~WMTeemGlyphs()
Nothing special with this constructor.
std::shared_ptr< WDataSetSphericalHarmonics > m_dataSet
Pointer to the treated data set.
WPropInt m_sliceIdProp
Property holding the slice ID.
Class representing a single module of OpenWalnut.
boost::filesystem::path m_localPath
The path where the module binary resides in.
virtual void properties()
Initialize properties in this function.
wlog::WStreamedLogger debugLog() const
Logger instance for comfortable debug logging.
void addConnector(std::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
std::shared_ptr< WProperties > m_properties
The property object for the module.
void ready()
Call this whenever your module is ready and can react on property changes.
WConditionSet m_moduleState
The internal state of the module.
virtual void activate()
Callback for m_active.
WPropBool m_active
True whenever the module should be active.
std::shared_ptr< WProgressCombiner > m_progress
Progress indicator used as parent for all progress' of this module.
virtual void connectors()
Initialize connectors in this function.
This only is a 3d double vector.
Class managing progress inside of modules.
Creates threads that computes a function in a multithreaded fashion.
virtual void wait()
Wait for all threads to stop.
virtual void run()
Starts the threads.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
Base class for all higher level values like tensors, vectors, matrices and so on.
size_t size() const
Get number of components the value consists of.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.