OpenWalnut  1.4.0
WDendrogramGeode.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <iostream>
26 
27 #include "../../graphicsEngine/WGEUtils.h"
28 
29 #include "WDendrogramGeode.h"
30 
31 /**
32  * Class implements a dendrogram as an osg geode
33  */
34 WDendrogramGeode::WDendrogramGeode( WHierarchicalTree* tree, size_t cluster, bool useLevel, size_t minClusterSize,
35  float xSize, float ySize, float xOffset, float yOffset ) :
36  osg::Geode(),
37  m_tree( tree ),
38  m_rootCluster( cluster ),
39  m_minClusterSize( minClusterSize ),
40  m_xSize( xSize ),
41  m_ySize( ySize ),
42  m_xOff( xOffset ),
43  m_yOff( yOffset ),
44  m_useLevel( useLevel )
45 {
46  create();
47 }
48 
50 {
51 }
52 
54 {
55  m_colors = osg::ref_ptr<osg::Vec4Array>( new osg::Vec4Array );
56 
57  m_vertexArray = new osg::Vec3Array;
58 
59  m_lineArray = new osg::DrawElementsUInt( osg::PrimitiveSet::LINES, 0 );
60 
61  float xMax = static_cast<float>( m_tree->size( m_rootCluster ) - 1 );
62 
63  m_xMult = m_xSize / xMax;
64 
65 
66  if( m_useLevel )
67  {
68  layoutLevel( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
69  float yMax = m_tree->getLevel( m_rootCluster );
70  m_yMult = m_ySize / yMax;
71  }
72  else
73  {
74  layoutValue( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
75  m_yMult = m_ySize;
76  }
77 
78  for( size_t i = 0; i < m_vertexArray->size(); ++i )
79  {
80  (*m_vertexArray)[i].x() = (*m_vertexArray)[i].x() * m_xMult + m_xOff;
81  (*m_vertexArray)[i].y() = (*m_vertexArray)[i].y() * m_yMult + m_yOff;
82  }
83 
84  osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry() );
85 
86  geometry->setVertexArray( m_vertexArray );
87 
88  geometry->addPrimitiveSet( m_lineArray );
89 
90  geometry->setColorArray( m_colors );
91  geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
92 
93  osg::StateSet* state = geometry->getOrCreateStateSet();
94  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
95 
96  addDrawable( geometry );
97 }
98 
99 void WDendrogramGeode::layoutLevel( size_t cluster, float left, float right )
100 {
101  float height = m_tree->getLevel( cluster );
102 
103  float size = right - left;
104 
105  if( m_tree->getLevel( cluster ) > 0 )
106  {
107  size_t leftCluster = m_tree->getChildren( cluster ).first;
108  size_t rightCluster = m_tree->getChildren( cluster ).second;
109 
110  float leftHeight = m_tree->getLevel( leftCluster );
111  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
112 
113  float rightHeight = m_tree->getLevel( rightCluster );
114  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
115 
116  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
117  //if( rightSize < 2 )
118  {
119  // left cluster is much bigger, draw only left
120  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
121  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), leftHeight, 0 ) );
122 
123  m_lineArray->push_back( m_vertexArray->size() - 2 );
124  m_lineArray->push_back( m_vertexArray->size() - 1 );
125 
126  m_colors->push_back( m_tree->getColor( cluster ) );
127  m_colors->push_back( m_tree->getColor( cluster ) );
128 
129  layoutLevel( leftCluster, left, right );
130  }
131  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
132  //else if( leftSize < 2 )
133  {
134  // right cluster is much bigger, draw only right
135  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
136  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), rightHeight, 0 ) );
137 
138  m_lineArray->push_back( m_vertexArray->size() - 2 );
139  m_lineArray->push_back( m_vertexArray->size() - 1 );
140 
141  m_colors->push_back( m_tree->getColor( cluster ) );
142  m_colors->push_back( m_tree->getColor( cluster ) );
143 
144  layoutLevel( rightCluster, left, right );
145  }
146  else
147  {
148  float mult = size / ( leftSize + rightSize );
149 
150  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), height, 0 ) );
151  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), height, 0 ) );
152 
153  m_lineArray->push_back( m_vertexArray->size() - 2 );
154  m_lineArray->push_back( m_vertexArray->size() - 1 );
155 
156  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), leftHeight, 0 ) );
157  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), rightHeight, 0 ) );
158 
159  m_colors->push_back( m_tree->getColor( cluster ) );
160  m_colors->push_back( m_tree->getColor( cluster ) );
161  m_colors->push_back( m_tree->getColor( cluster ) );
162  m_colors->push_back( m_tree->getColor( cluster ) );
163 
164  m_lineArray->push_back( m_vertexArray->size() - 4 );
165  m_lineArray->push_back( m_vertexArray->size() - 2 );
166  m_lineArray->push_back( m_vertexArray->size() - 3 );
167  m_lineArray->push_back( m_vertexArray->size() - 1 );
168 
169  layoutLevel( leftCluster, left, left + leftSize * mult );
170  layoutLevel( rightCluster, right - rightSize * mult, right );
171  }
172  }
173 }
174 
175 void WDendrogramGeode::layoutValue( size_t cluster, float left, float right )
176 {
177  float height = m_tree->getCustomData( cluster );
178 
179  float size = right - left;
180 
181  if( m_tree->getLevel( cluster ) > 0 )
182  {
183  size_t leftCluster = m_tree->getChildren( cluster ).first;
184  size_t rightCluster = m_tree->getChildren( cluster ).second;
185 
186  float leftHeight = m_tree->getCustomData( leftCluster );
187  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
188 
189  float rightHeight = m_tree->getCustomData( rightCluster );
190  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
191 
192  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
193  //if( rightSize < 2 )
194  {
195  // left cluster is much bigger, draw only left
196  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
197  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), leftHeight, 0 ) );
198 
199  m_lineArray->push_back( m_vertexArray->size() - 2 );
200  m_lineArray->push_back( m_vertexArray->size() - 1 );
201 
202  m_colors->push_back( m_tree->getColor( cluster ) );
203  m_colors->push_back( m_tree->getColor( cluster ) );
204 
205  layoutValue( leftCluster, left, right );
206  }
207  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
208  //else if( leftSize < 2 )
209  {
210  // right cluster is much bigger, draw only right
211  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
212  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), rightHeight, 0 ) );
213 
214  m_lineArray->push_back( m_vertexArray->size() - 2 );
215  m_lineArray->push_back( m_vertexArray->size() - 1 );
216 
217  m_colors->push_back( m_tree->getColor( cluster ) );
218  m_colors->push_back( m_tree->getColor( cluster ) );
219 
220  layoutValue( rightCluster, left, right );
221  }
222  else
223  {
224  float mult = size / ( leftSize + rightSize );
225 
226  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), height, 0 ) );
227  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), height, 0 ) );
228 
229  m_lineArray->push_back( m_vertexArray->size() - 2 );
230  m_lineArray->push_back( m_vertexArray->size() - 1 );
231 
232  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), leftHeight, 0 ) );
233  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), rightHeight, 0 ) );
234 
235  m_colors->push_back( m_tree->getColor( cluster ) );
236  m_colors->push_back( m_tree->getColor( cluster ) );
237  m_colors->push_back( m_tree->getColor( cluster ) );
238  m_colors->push_back( m_tree->getColor( cluster ) );
239 
240  m_lineArray->push_back( m_vertexArray->size() - 4 );
241  m_lineArray->push_back( m_vertexArray->size() - 2 );
242  m_lineArray->push_back( m_vertexArray->size() - 3 );
243  m_lineArray->push_back( m_vertexArray->size() - 1 );
244 
245  layoutValue( leftCluster, left, left + leftSize * mult );
246  layoutValue( rightCluster, right - rightSize * mult, right );
247  }
248  }
249 }
250 
251 size_t WDendrogramGeode::getClickedCluster( int xClick, int yClick )
252 {
253  m_xClicked = ( xClick - m_xOff ) / m_xSize * ( m_tree->size( m_rootCluster ) );
254 
256 
257  if( m_useLevel )
258  {
259  m_yClicked = ( yClick - m_yOff ) / m_ySize * ( m_tree->getLevel( m_rootCluster ) );
260  getClickClusterRecursive( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
261  }
262  else
263  {
264  m_yClicked = ( yClick - m_yOff );
265  getClickClusterRecursive2( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
266  }
267 
268  return m_clickedCluster;
269 }
270 
271 void WDendrogramGeode::getClickClusterRecursive2( size_t cluster, float left, float right )
272 {
273  int height = static_cast<int>( m_tree->getCustomData( cluster ) * m_ySize );
274 
275  if( abs( height - m_yClicked ) < 2 )
276  {
277  m_clickedCluster = cluster;
278  return;
279  }
280 
281  int size = right - left;
282 
283  if( m_tree->getLevel( cluster ) > 0 )
284  {
285  size_t leftCluster = m_tree->getChildren( cluster ).first;
286  size_t rightCluster = m_tree->getChildren( cluster ).second;
287 
288  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
289  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
290 
291  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
292  {
293  // left cluster is much bigger, draw only left
294  getClickClusterRecursive2( leftCluster, left, right );
295  }
296  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
297  {
298  // right cluster is much bigger, draw only right
299  getClickClusterRecursive2( rightCluster, left, right );
300  }
301  else
302  {
303  float mult = size / ( leftSize + rightSize );
304 
305  if( m_xClicked < left + leftSize * mult )
306  {
307  getClickClusterRecursive2( leftCluster, left, left + leftSize * mult );
308  }
309  else
310  {
311  getClickClusterRecursive2( rightCluster, right - rightSize * mult, right );
312  }
313  }
314  }
315 }
316 
317 void WDendrogramGeode::getClickClusterRecursive( size_t cluster, float left, float right )
318 {
319  int height = m_tree->getLevel( cluster );
320 
321  if( height == m_yClicked )
322  {
323  m_clickedCluster = cluster;
324  return;
325  }
326 
327  int size = right - left;
328 
329  if( m_tree->getLevel( cluster ) > 0 )
330  {
331  size_t leftCluster = m_tree->getChildren( cluster ).first;
332  size_t rightCluster = m_tree->getChildren( cluster ).second;
333 
334  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
335  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
336 
337  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
338  {
339  // left cluster is much bigger, draw only left
340  getClickClusterRecursive( leftCluster, left, right );
341  }
342  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
343  {
344  // right cluster is much bigger, draw only right
345  getClickClusterRecursive( rightCluster, left, right );
346  }
347  else
348  {
349  float mult = size / ( leftSize + rightSize );
350 
351  if( m_xClicked < left + leftSize * mult )
352  {
353  getClickClusterRecursive( leftCluster, left, left + leftSize * mult );
354  }
355  else
356  {
357  getClickClusterRecursive( rightCluster, right - rightSize * mult, right );
358  }
359  }
360  }
361 }
~WDendrogramGeode()
destructor
WColor getColor(size_t cluster)
getter
float m_yMult
helper variable for the recursive function
float m_xMult
helper variable for the recursive function
float m_yOff
y offset
std::pair< size_t, size_t > getChildren(size_t cluster)
getter
float m_ySize
y size in pixel of the final dendrogram
size_t m_clickedCluster
the clicked cluster
size_t getClickedCluster(int xClick, int yClick)
calculate which cluster was clicked from given pixel coordinates
void layoutLevel(size_t cluster, float left, float right)
recursive funtion that lays out the tree from top to bottom, height of the joins is determined by the...
void create()
helper function the starts the layout process from the input data in the constructor ...
osg::Vec3Array * m_vertexArray
vertex array
bool m_useLevel
flag indicating if the level or the value of a cluster will be used for the height of join ...
void getClickClusterRecursive2(size_t cluster, float left, float right)
recurse function that follows the layout to determine the cluster from pixel coordinates, used when the customData value is used for height
base class for hierarchical tree implementations
size_t m_rootCluster
top cluster to draw the tree from
osg::ref_ptr< osg::Vec4Array > m_colors
color array
float m_xSize
x size in pixel of the final dendrogram
int m_xClicked
stores the click position for use int he recursive function
float getCustomData(size_t cluster)
getter
float m_xOff
x offset
void layoutValue(size_t cluster, float left, float right)
recursive funtion that lays out the tree from top to bottom, height of the joins is determined by the...
void getClickClusterRecursive(size_t cluster, float left, float right)
recurse function that follows the layout to determine the cluster from pixel coordinates, used when the level of the cluster is used for height
WDendrogramGeode(WHierarchicalTree *tree, size_t cluster, bool useLevel=true, size_t minClusterSize=1, float xSize=1000.f, float ySize=500.f, float xOffset=0.0f, float yOffset=0.0f)
constructor
size_t size(size_t cluster)
getter
osg::DrawElementsUInt * m_lineArray
line array
size_t m_minClusterSize
minimum cluster size to be considered while laying out the dendrogram
int m_yClicked
stores the click position for use int he recursive function
size_t getLevel(size_t cluster)
getter
WHierarchicalTree * m_tree
the tree to work on