OpenWalnut  1.3.1
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 #include "WDendrogramGeode.h"
29 
30 /**
31  * Class implements a dendrogram as an osg geode
32  */
33 WDendrogramGeode::WDendrogramGeode( WHierarchicalTree* tree, size_t cluster, bool useLevel, size_t minClusterSize,
34  float xSize, float ySize, float xOffset, float yOffset ) :
35  osg::Geode(),
36  m_tree( tree ),
37  m_rootCluster( cluster ),
38  m_minClusterSize( minClusterSize ),
39  m_xSize( xSize ),
40  m_ySize( ySize ),
41  m_xOff( xOffset ),
42  m_yOff( yOffset ),
43  m_useLevel( useLevel )
44 {
45  create();
46 }
47 
49 {
50 }
51 
53 {
54  m_colors = osg::ref_ptr<osg::Vec4Array>( new osg::Vec4Array );
55 
56  m_vertexArray = new osg::Vec3Array;
57 
58  m_lineArray = new osg::DrawElementsUInt( osg::PrimitiveSet::LINES, 0 );
59 
60  float xMax = static_cast<float>( m_tree->size( m_rootCluster ) - 1 );
61 
62  m_xMult = m_xSize / xMax;
63 
64 
65  if( m_useLevel )
66  {
67  layoutLevel( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
68  float yMax = m_tree->getLevel( m_rootCluster );
69  m_yMult = m_ySize / yMax;
70  }
71  else
72  {
73  layoutValue( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
74  m_yMult = m_ySize;
75  }
76 
77  for( size_t i = 0; i < m_vertexArray->size(); ++i )
78  {
79  (*m_vertexArray)[i].x() = (*m_vertexArray)[i].x() * m_xMult + m_xOff;
80  (*m_vertexArray)[i].y() = (*m_vertexArray)[i].y() * m_yMult + m_yOff;
81  }
82 
83  osg::ref_ptr< osg::Geometry > geometry = osg::ref_ptr< osg::Geometry >( new osg::Geometry() );
84 
85  geometry->setVertexArray( m_vertexArray );
86 
87  geometry->addPrimitiveSet( m_lineArray );
88 
89  geometry->setColorArray( m_colors );
90  geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
91 
92  osg::StateSet* state = geometry->getOrCreateStateSet();
93  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
94 
95  addDrawable( geometry );
96 }
97 
98 void WDendrogramGeode::layoutLevel( size_t cluster, float left, float right )
99 {
100  float height = m_tree->getLevel( cluster );
101 
102  float size = right - left;
103 
104  if( m_tree->getLevel( cluster ) > 0 )
105  {
106  size_t leftCluster = m_tree->getChildren( cluster ).first;
107  size_t rightCluster = m_tree->getChildren( cluster ).second;
108 
109  float leftHeight = m_tree->getLevel( leftCluster );
110  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
111 
112  float rightHeight = m_tree->getLevel( rightCluster );
113  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
114 
115  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
116  //if( rightSize < 2 )
117  {
118  // left cluster is much bigger, draw only left
119  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
120  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), leftHeight, 0 ) );
121 
122  m_lineArray->push_back( m_vertexArray->size() - 2 );
123  m_lineArray->push_back( m_vertexArray->size() - 1 );
124 
125  m_colors->push_back( m_tree->getColor( cluster ) );
126  m_colors->push_back( m_tree->getColor( cluster ) );
127 
128  layoutLevel( leftCluster, left, right );
129  }
130  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
131  //else if( leftSize < 2 )
132  {
133  // right cluster is much bigger, draw only right
134  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
135  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), rightHeight, 0 ) );
136 
137  m_lineArray->push_back( m_vertexArray->size() - 2 );
138  m_lineArray->push_back( m_vertexArray->size() - 1 );
139 
140  m_colors->push_back( m_tree->getColor( cluster ) );
141  m_colors->push_back( m_tree->getColor( cluster ) );
142 
143  layoutLevel( rightCluster, left, right );
144  }
145  else
146  {
147  float mult = size / ( leftSize + rightSize );
148 
149  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), height, 0 ) );
150  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), height, 0 ) );
151 
152  m_lineArray->push_back( m_vertexArray->size() - 2 );
153  m_lineArray->push_back( m_vertexArray->size() - 1 );
154 
155  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), leftHeight, 0 ) );
156  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), rightHeight, 0 ) );
157 
158  m_colors->push_back( m_tree->getColor( cluster ) );
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 
163  m_lineArray->push_back( m_vertexArray->size() - 4 );
164  m_lineArray->push_back( m_vertexArray->size() - 2 );
165  m_lineArray->push_back( m_vertexArray->size() - 3 );
166  m_lineArray->push_back( m_vertexArray->size() - 1 );
167 
168  layoutLevel( leftCluster, left, left + leftSize * mult );
169  layoutLevel( rightCluster, right - rightSize * mult, right );
170  }
171  }
172 }
173 
174 void WDendrogramGeode::layoutValue( size_t cluster, float left, float right )
175 {
176  float height = m_tree->getCustomData( cluster );
177 
178  float size = right - left;
179 
180  if( m_tree->getLevel( cluster ) > 0 )
181  {
182  size_t leftCluster = m_tree->getChildren( cluster ).first;
183  size_t rightCluster = m_tree->getChildren( cluster ).second;
184 
185  float leftHeight = m_tree->getCustomData( leftCluster );
186  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
187 
188  float rightHeight = m_tree->getCustomData( rightCluster );
189  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
190 
191  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
192  //if( rightSize < 2 )
193  {
194  // left cluster is much bigger, draw only left
195  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
196  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), leftHeight, 0 ) );
197 
198  m_lineArray->push_back( m_vertexArray->size() - 2 );
199  m_lineArray->push_back( m_vertexArray->size() - 1 );
200 
201  m_colors->push_back( m_tree->getColor( cluster ) );
202  m_colors->push_back( m_tree->getColor( cluster ) );
203 
204  layoutValue( leftCluster, left, right );
205  }
206  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
207  //else if( leftSize < 2 )
208  {
209  // right cluster is much bigger, draw only right
210  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), height, 0 ) );
211  m_vertexArray->push_back( osg::Vec3( ( left + size / 2.0 ), rightHeight, 0 ) );
212 
213  m_lineArray->push_back( m_vertexArray->size() - 2 );
214  m_lineArray->push_back( m_vertexArray->size() - 1 );
215 
216  m_colors->push_back( m_tree->getColor( cluster ) );
217  m_colors->push_back( m_tree->getColor( cluster ) );
218 
219  layoutValue( rightCluster, left, right );
220  }
221  else
222  {
223  float mult = size / ( leftSize + rightSize );
224 
225  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), height, 0 ) );
226  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), height, 0 ) );
227 
228  m_lineArray->push_back( m_vertexArray->size() - 2 );
229  m_lineArray->push_back( m_vertexArray->size() - 1 );
230 
231  m_vertexArray->push_back( osg::Vec3( ( left + leftSize * mult / 2.0 ), leftHeight, 0 ) );
232  m_vertexArray->push_back( osg::Vec3( ( right - rightSize * mult / 2.0 ), rightHeight, 0 ) );
233 
234  m_colors->push_back( m_tree->getColor( cluster ) );
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 
239  m_lineArray->push_back( m_vertexArray->size() - 4 );
240  m_lineArray->push_back( m_vertexArray->size() - 2 );
241  m_lineArray->push_back( m_vertexArray->size() - 3 );
242  m_lineArray->push_back( m_vertexArray->size() - 1 );
243 
244  layoutValue( leftCluster, left, left + leftSize * mult );
245  layoutValue( rightCluster, right - rightSize * mult, right );
246  }
247  }
248 }
249 
250 size_t WDendrogramGeode::getClickedCluster( int xClick, int yClick )
251 {
252  m_xClicked = ( xClick - m_xOff ) / m_xSize * ( m_tree->size( m_rootCluster ) );
253 
255 
256  if( m_useLevel )
257  {
258  m_yClicked = ( yClick - m_yOff ) / m_ySize * ( m_tree->getLevel( m_rootCluster ) );
259  getClickClusterRecursive( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
260  }
261  else
262  {
263  m_yClicked = ( yClick - m_yOff );
264  getClickClusterRecursive2( m_rootCluster, 0.0f, static_cast<float>( m_tree->size( m_rootCluster ) - 1 ) );
265  }
266 
267  return m_clickedCluster;
268 }
269 
270 void WDendrogramGeode::getClickClusterRecursive2( size_t cluster, float left, float right )
271 {
272  int height = static_cast<int>( m_tree->getCustomData( cluster ) * m_ySize );
273 
274  if( abs( height - m_yClicked ) < 2 )
275  {
276  m_clickedCluster = cluster;
277  return;
278  }
279 
280  int size = right - left;
281 
282  if( m_tree->getLevel( cluster ) > 0 )
283  {
284  size_t leftCluster = m_tree->getChildren( cluster ).first;
285  size_t rightCluster = m_tree->getChildren( cluster ).second;
286 
287  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
288  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
289 
290  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
291  {
292  // left cluster is much bigger, draw only left
293  getClickClusterRecursive2( leftCluster, left, right );
294  }
295  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
296  {
297  // right cluster is much bigger, draw only right
298  getClickClusterRecursive2( rightCluster, left, right );
299  }
300  else
301  {
302  float mult = size / ( leftSize + rightSize );
303 
304  if( m_xClicked < left + leftSize * mult )
305  {
306  getClickClusterRecursive2( leftCluster, left, left + leftSize * mult );
307  }
308  else
309  {
310  getClickClusterRecursive2( rightCluster, right - rightSize * mult, right );
311  }
312  }
313  }
314 }
315 
316 void WDendrogramGeode::getClickClusterRecursive( size_t cluster, float left, float right )
317 {
318  int height = m_tree->getLevel( cluster );
319 
320  if( height == m_yClicked )
321  {
322  m_clickedCluster = cluster;
323  return;
324  }
325 
326  int size = right - left;
327 
328  if( m_tree->getLevel( cluster ) > 0 )
329  {
330  size_t leftCluster = m_tree->getChildren( cluster ).first;
331  size_t rightCluster = m_tree->getChildren( cluster ).second;
332 
333  float leftSize = static_cast<float>( m_tree->size( leftCluster ) );
334  float rightSize = static_cast<float>( m_tree->size( rightCluster ) );
335 
336  if( ( leftSize >= m_minClusterSize ) && ( rightSize < m_minClusterSize ) )
337  {
338  // left cluster is much bigger, draw only left
339  getClickClusterRecursive( leftCluster, left, right );
340  }
341  else if( ( rightSize >= m_minClusterSize ) && ( leftSize < m_minClusterSize ) )
342  {
343  // right cluster is much bigger, draw only right
344  getClickClusterRecursive( rightCluster, left, right );
345  }
346  else
347  {
348  float mult = size / ( leftSize + rightSize );
349 
350  if( m_xClicked < left + leftSize * mult )
351  {
352  getClickClusterRecursive( leftCluster, left, left + leftSize * mult );
353  }
354  else
355  {
356  getClickClusterRecursive( rightCluster, right - rightSize * mult, right );
357  }
358  }
359  }
360 }