OpenWalnut  1.5.0dev
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 }
362 
364 {
365  return ( pos[0] >= m_xOff && pos[0] <= m_xOff + m_xSize &&
366  pos[1] >= m_yOff && pos[1] <= m_yOff + m_ySize );
367 }
368 
bool m_useLevel
flag indicating if the level or the value of a cluster will be used for the height of join
void getClickClusterRecursive(size_t cluster, float left, float right)
recurse function that follows the layout to determine the cluster from pixel coordinates,...
size_t getClickedCluster(int xClick, int yClick)
calculate which cluster was clicked from given pixel coordinates
int m_xClicked
stores the click position for use int he recursive function
int m_yClicked
stores the click position for use int he recursive function
size_t m_rootCluster
top cluster to draw the tree from
float m_xMult
helper variable for the recursive function
osg::ref_ptr< osg::Vec4Array > m_colors
color array
WHierarchicalTree * m_tree
the tree to work on
float m_ySize
y size in pixel of the final dendrogram
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...
bool inDendrogramArea(const WVector2f &pos) const
calculates if the given position is within the view area of the dendrogram
~WDendrogramGeode()
destructor
float m_xOff
x offset
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
osg::DrawElementsUInt * m_lineArray
line array
size_t m_minClusterSize
minimum cluster size to be considered while laying out the dendrogram
size_t m_clickedCluster
the clicked cluster
float m_yMult
helper variable for the recursive function
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...
float m_yOff
y offset
osg::Vec3Array * m_vertexArray
vertex array
void create()
helper function the starts the layout process from the input data in the constructor
float m_xSize
x size in pixel of the final dendrogram
void getClickClusterRecursive2(size_t cluster, float left, float right)
recurse function that follows the layout to determine the cluster from pixel coordinates,...
base class for hierarchical tree implementations
size_t size(size_t cluster) const
getter
std::pair< size_t, size_t > getChildren(size_t cluster) const
getter
WColor getColor(size_t cluster) const
getter
float getCustomData(size_t cluster) const
getter
size_t getLevel(size_t cluster) const
getter
A fixed size matrix class.
Definition: WMatrixFixed.h:150