OpenWalnut  1.4.0
WDendrogramGeode.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <iostream>
00026 
00027 #include "../../graphicsEngine/WGEUtils.h"
00028 
00029 #include "WDendrogramGeode.h"
00030 
00031 /**
00032  * Class implements a dendrogram as an osg geode
00033  */
00034 WDendrogramGeode::WDendrogramGeode( WHierarchicalTree* tree, size_t cluster, bool useLevel, size_t minClusterSize,
00035                                     float xSize, float ySize, float xOffset, float yOffset ) :
00036     osg::Geode(),
00037     m_tree( tree ),
00038     m_rootCluster( cluster ),
00039     m_minClusterSize( minClusterSize ),
00040     m_xSize( xSize ),
00041     m_ySize( ySize ),
00042     m_xOff( xOffset ),
00043     m_yOff( yOffset ),
00044     m_useLevel( useLevel )
00045 {
00046     create();
00047 }
00048 
00049 WDendrogramGeode::~WDendrogramGeode()
00050 {
00051 }
00052 
00053 void WDendrogramGeode::create()
00054 {
00055     m_colors = osg::ref_ptr<osg::Vec4Array>( new osg::Vec4Array );
00056 
00057     m_vertexArray = new osg::Vec3Array;
00058 
00059     m_lineArray = new osg::DrawElementsUInt( osg::PrimitiveSet::LINES, 0 );
00060 
00061     float xMax = static_cast<float>( m_tree->size( m_rootCluster ) - 1 );
00062 
00063     m_xMult = m_xSize / xMax;
00064 
00065 
00066     if( m_useLevel )
00067     {
00068         layoutLevel( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
00069         float yMax = m_tree->getLevel( m_rootCluster );
00070         m_yMult = m_ySize / yMax;
00071     }
00072     else
00073     {
00074         layoutValue( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
00075         m_yMult = m_ySize;
00076     }
00077 
00078     for( size_t i = 0; i < m_vertexArray->size(); ++i )
00079     {
00080         (*m_vertexArray)[i].x() = (*m_vertexArray)[i].x() * m_xMult + m_xOff;
00081         (*m_vertexArray)[i].y() = (*m_vertexArray)[i].y() * m_yMult + m_yOff;
00082     }
00083 
00084     osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry() );
00085 
00086     geometry->setVertexArray( m_vertexArray );
00087 
00088     geometry->addPrimitiveSet( m_lineArray );
00089 
00090     geometry->setColorArray( m_colors );
00091     geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
00092 
00093     osg::StateSet* state = geometry->getOrCreateStateSet();
00094     state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
00095 
00096     addDrawable( geometry );
00097 }
00098 
00099 void WDendrogramGeode::layoutLevel( size_t cluster, float left, float right )
00100 {
00101     float height = m_tree->getLevel( cluster );
00102 
00103     float size = right - left;
00104 
00105     if( m_tree->getLevel( cluster ) > 0 )
00106     {
00107         size_t leftCluster = m_tree->getChildren( cluster ).first;
00108         size_t rightCluster = m_tree->getChildren( cluster ).second;
00109 
00110         float leftHeight = m_tree->getLevel( leftCluster );
00111         float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
00112 
00113         float rightHeight = m_tree->getLevel( rightCluster );
00114         float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
00115 
00116         if( ( leftSize >= m_minClusterSize ) &&  ( rightSize < m_minClusterSize ) )
00117         //if( rightSize < 2 )
00118         {
00119             // left cluster is much bigger, draw only left
00120             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
00121             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), leftHeight, 0 ) );
00122 
00123             m_lineArray->push_back( m_vertexArray->size() - 2 );
00124             m_lineArray->push_back( m_vertexArray->size() - 1 );
00125 
00126             m_colors->push_back( m_tree->getColor( cluster ) );
00127             m_colors->push_back( m_tree->getColor( cluster ) );
00128 
00129             layoutLevel( leftCluster, left, right );
00130         }
00131         else if( ( rightSize >= m_minClusterSize ) &&  ( leftSize < m_minClusterSize ) )
00132         //else if( leftSize < 2 )
00133         {
00134             // right cluster is much bigger, draw only right
00135             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
00136             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), rightHeight, 0 ) );
00137 
00138             m_lineArray->push_back( m_vertexArray->size() - 2 );
00139             m_lineArray->push_back( m_vertexArray->size() - 1 );
00140 
00141             m_colors->push_back( m_tree->getColor( cluster ) );
00142             m_colors->push_back( m_tree->getColor( cluster ) );
00143 
00144             layoutLevel( rightCluster, left, right );
00145         }
00146         else
00147         {
00148             float mult = size / ( leftSize + rightSize );
00149 
00150             m_vertexArray->push_back( osg::Vec3( ( left  + leftSize * mult  / 2.0 ), height, 0 ) );
00151             m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), height, 0 ) );
00152 
00153             m_lineArray->push_back( m_vertexArray->size() - 2 );
00154             m_lineArray->push_back( m_vertexArray->size() - 1 );
00155 
00156             m_vertexArray->push_back( osg::Vec3( ( left  + leftSize * mult  / 2.0 ), leftHeight, 0 ) );
00157             m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), rightHeight, 0 ) );
00158 
00159             m_colors->push_back( m_tree->getColor( cluster ) );
00160             m_colors->push_back( m_tree->getColor( cluster ) );
00161             m_colors->push_back( m_tree->getColor( cluster ) );
00162             m_colors->push_back( m_tree->getColor( cluster ) );
00163 
00164             m_lineArray->push_back( m_vertexArray->size() - 4 );
00165             m_lineArray->push_back( m_vertexArray->size() - 2 );
00166             m_lineArray->push_back( m_vertexArray->size() - 3 );
00167             m_lineArray->push_back( m_vertexArray->size() - 1 );
00168 
00169             layoutLevel( leftCluster, left, left + leftSize * mult );
00170             layoutLevel( rightCluster, right - rightSize * mult, right );
00171         }
00172     }
00173 }
00174 
00175 void WDendrogramGeode::layoutValue( size_t cluster, float left, float right )
00176 {
00177     float height = m_tree->getCustomData( cluster );
00178 
00179     float size = right - left;
00180 
00181     if( m_tree->getLevel( cluster ) > 0 )
00182     {
00183         size_t leftCluster = m_tree->getChildren( cluster ).first;
00184         size_t rightCluster = m_tree->getChildren( cluster ).second;
00185 
00186         float leftHeight = m_tree->getCustomData( leftCluster );
00187         float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
00188 
00189         float rightHeight = m_tree->getCustomData( rightCluster );
00190         float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
00191 
00192         if( ( leftSize >= m_minClusterSize ) &&  ( rightSize < m_minClusterSize ) )
00193         //if( rightSize < 2 )
00194         {
00195             // left cluster is much bigger, draw only left
00196             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
00197             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), leftHeight, 0 ) );
00198 
00199             m_lineArray->push_back( m_vertexArray->size() - 2 );
00200             m_lineArray->push_back( m_vertexArray->size() - 1 );
00201 
00202             m_colors->push_back( m_tree->getColor( cluster ) );
00203             m_colors->push_back( m_tree->getColor( cluster ) );
00204 
00205             layoutValue( leftCluster, left, right );
00206         }
00207         else if( ( rightSize >= m_minClusterSize ) &&  ( leftSize < m_minClusterSize ) )
00208         //else if( leftSize < 2 )
00209         {
00210             // right cluster is much bigger, draw only right
00211             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
00212             m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), rightHeight, 0 ) );
00213 
00214             m_lineArray->push_back( m_vertexArray->size() - 2 );
00215             m_lineArray->push_back( m_vertexArray->size() - 1 );
00216 
00217             m_colors->push_back( m_tree->getColor( cluster ) );
00218             m_colors->push_back( m_tree->getColor( cluster ) );
00219 
00220             layoutValue( rightCluster, left, right );
00221         }
00222         else
00223         {
00224             float mult = size / ( leftSize + rightSize );
00225 
00226             m_vertexArray->push_back( osg::Vec3( ( left  + leftSize * mult  / 2.0 ), height, 0 ) );
00227             m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), height, 0 ) );
00228 
00229             m_lineArray->push_back( m_vertexArray->size() - 2 );
00230             m_lineArray->push_back( m_vertexArray->size() - 1 );
00231 
00232             m_vertexArray->push_back( osg::Vec3( ( left  + leftSize * mult  / 2.0 ), leftHeight, 0 ) );
00233             m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), rightHeight, 0 ) );
00234 
00235             m_colors->push_back( m_tree->getColor( cluster ) );
00236             m_colors->push_back( m_tree->getColor( cluster ) );
00237             m_colors->push_back( m_tree->getColor( cluster ) );
00238             m_colors->push_back( m_tree->getColor( cluster ) );
00239 
00240             m_lineArray->push_back( m_vertexArray->size() - 4 );
00241             m_lineArray->push_back( m_vertexArray->size() - 2 );
00242             m_lineArray->push_back( m_vertexArray->size() - 3 );
00243             m_lineArray->push_back( m_vertexArray->size() - 1 );
00244 
00245             layoutValue( leftCluster, left, left + leftSize * mult );
00246             layoutValue( rightCluster, right - rightSize * mult, right );
00247         }
00248     }
00249 }
00250 
00251 size_t WDendrogramGeode::getClickedCluster( int xClick, int yClick )
00252 {
00253     m_xClicked = ( xClick - m_xOff ) / m_xSize * ( m_tree->size( m_rootCluster ) );
00254 
00255     m_clickedCluster = m_rootCluster;
00256 
00257     if( m_useLevel )
00258     {
00259         m_yClicked = ( yClick - m_yOff ) / m_ySize * ( m_tree->getLevel( m_rootCluster ) );
00260         getClickClusterRecursive( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
00261     }
00262     else
00263     {
00264         m_yClicked = ( yClick - m_yOff );
00265         getClickClusterRecursive2( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
00266     }
00267 
00268     return m_clickedCluster;
00269 }
00270 
00271 void WDendrogramGeode::getClickClusterRecursive2( size_t cluster, float left, float right )
00272 {
00273     int height = static_cast<int>( m_tree->getCustomData( cluster ) * m_ySize );
00274 
00275     if( abs( height - m_yClicked ) < 2 )
00276     {
00277         m_clickedCluster = cluster;
00278         return;
00279     }
00280 
00281     int size = right - left;
00282 
00283     if( m_tree->getLevel( cluster ) > 0 )
00284     {
00285         size_t leftCluster = m_tree->getChildren( cluster ).first;
00286         size_t rightCluster = m_tree->getChildren( cluster ).second;
00287 
00288         float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
00289         float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
00290 
00291         if( ( leftSize >= m_minClusterSize ) &&  ( rightSize < m_minClusterSize ) )
00292         {
00293             // left cluster is much bigger, draw only left
00294             getClickClusterRecursive2( leftCluster, left, right );
00295         }
00296         else if( ( rightSize >= m_minClusterSize ) &&  ( leftSize < m_minClusterSize ) )
00297         {
00298             // right cluster is much bigger, draw only right
00299             getClickClusterRecursive2( rightCluster, left, right );
00300         }
00301         else
00302         {
00303             float mult = size / ( leftSize + rightSize );
00304 
00305             if( m_xClicked < left + leftSize * mult )
00306             {
00307                 getClickClusterRecursive2( leftCluster, left, left + leftSize * mult );
00308             }
00309             else
00310             {
00311                 getClickClusterRecursive2( rightCluster, right - rightSize * mult, right );
00312             }
00313         }
00314     }
00315 }
00316 
00317 void WDendrogramGeode::getClickClusterRecursive( size_t cluster, float left, float right )
00318 {
00319     int height = m_tree->getLevel( cluster );
00320 
00321     if( height == m_yClicked )
00322     {
00323         m_clickedCluster = cluster;
00324         return;
00325     }
00326 
00327     int size = right - left;
00328 
00329     if( m_tree->getLevel( cluster ) > 0 )
00330     {
00331         size_t leftCluster = m_tree->getChildren( cluster ).first;
00332         size_t rightCluster = m_tree->getChildren( cluster ).second;
00333 
00334         float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
00335         float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
00336 
00337         if( ( leftSize >= m_minClusterSize ) &&  ( rightSize < m_minClusterSize ) )
00338         {
00339             // left cluster is much bigger, draw only left
00340             getClickClusterRecursive( leftCluster, left, right );
00341         }
00342         else if( ( rightSize >= m_minClusterSize ) &&  ( leftSize < m_minClusterSize ) )
00343         {
00344             // right cluster is much bigger, draw only right
00345             getClickClusterRecursive( rightCluster, left, right );
00346         }
00347         else
00348         {
00349             float mult = size / ( leftSize + rightSize );
00350 
00351             if( m_xClicked < left + leftSize * mult )
00352             {
00353                 getClickClusterRecursive( leftCluster, left, left + leftSize * mult );
00354             }
00355             else
00356             {
00357                 getClickClusterRecursive( rightCluster, right - rightSize * mult, right );
00358             }
00359         }
00360     }
00361 }