1 |
/* |
2 |
* Copyright 2008-2013 Steven Dalton |
3 |
* |
4 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
5 |
* you may not use this file except in compliance with the License. |
6 |
* You may obtain a copy of the License at |
7 |
* |
8 |
* http://www.apache.org/licenses/LICENSE-2.0 |
9 |
* |
10 |
* Unless required by applicable law or agreed to in writing, software |
11 |
* distributed under the License is distributed on an "AS IS" BASIS, |
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 |
* See the License for the specific language governing permissions and |
14 |
* limitations under the License. |
15 |
*/ |
16 |
|
17 |
/** |
18 |
* @file matrix_canvas.cc |
19 |
* An implementation of a matrix canvas class to display a sparse matrix |
20 |
* for the spy program. |
21 |
*/ |
22 |
|
23 |
/* |
24 |
* David Gleich |
25 |
* 21 November 2006 |
26 |
* Copyright, Stanford University |
27 |
*/ |
28 |
|
29 |
#include <stdlib.h> |
30 |
#include <string> |
31 |
#include <limits> |
32 |
#include <cmath> |
33 |
#include <algorithm> |
34 |
#include <utility> |
35 |
|
36 |
#include <cusp/opengl/spy/glut_2d_canvas.h> |
37 |
#include <cusp/opengl/spy/matrix_data_panel.h> |
38 |
#include <cusp/opengl/spy/matrix_data_cursor.h> |
39 |
#include <cusp/opengl/spy/matrix_canvas.h> |
40 |
#include <cusp/opengl/spy/colormaps.h> |
41 |
|
42 |
#include <thrust/iterator/constant_iterator.h> |
43 |
#include <thrust/iterator/counting_iterator.h> |
44 |
|
45 |
namespace cusp |
46 |
{ |
47 |
namespace opengl |
48 |
{ |
49 |
namespace spy |
50 |
{ |
51 |
|
52 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
53 |
matrix_canvas<IndexType,ValueType,MemorySpace>::matrix_canvas(int w, int h) |
54 |
: |
55 |
glut_2d_canvas(w,h,"spy"), // initialize the window first |
56 |
// the order of the rest is the order in which the variables are |
57 |
// declared in the class declaration |
58 |
p_offset(panel_offset), p_height(panel_height), |
59 |
data_panel(glut_id, width-2*p_offset, std::max(height/2,p_height), p_offset, p_offset), |
60 |
matrix_display_list(0), |
61 |
data_panel_visible(false), |
62 |
data_cursor(0,0), |
63 |
matrix_filename(""), |
64 |
matrix_loaded(false), |
65 |
point_alpha(0.5f), |
66 |
normalization_state(no_normalization), |
67 |
permutation_state(no_permutation), |
68 |
colormap_state(rainbow_colormap), |
69 |
colormap((float *)spring_color_map, |
70 |
sizeof(spring_color_map)/sizeof(spring_color_map[0])), |
71 |
colormap_invert(false), |
72 |
rperm_loaded(false), |
73 |
cperm_loaded(false) |
74 |
{ |
75 |
border_color[0]=1.0f; |
76 |
border_color[1]=1.0f; |
77 |
border_color[2]=1.0f; |
78 |
} |
79 |
|
80 |
|
81 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
82 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::post_constructor() |
83 |
{ |
84 |
init_window(); |
85 |
init_menu(); |
86 |
init_display_list(); |
87 |
|
88 |
set_zoom(0.95f); |
89 |
|
90 |
show_data_panel(); |
91 |
} |
92 |
|
93 |
/** |
94 |
* This function draws the matrix. |
95 |
*/ |
96 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
97 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::draw() |
98 |
{ |
99 |
if (!matrix_loaded) { |
100 |
return; |
101 |
} |
102 |
|
103 |
int m = _m.num_rows; |
104 |
int n = _m.num_cols; |
105 |
|
106 |
glEnable(GL_BLEND); |
107 |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
108 |
|
109 |
// border |
110 |
glPointSize(1.0); |
111 |
glColor3f(border_color[0], border_color[1], border_color[2]); |
112 |
glBegin(GL_LINE_LOOP); |
113 |
glVertex2f(-0.5f, -0.5f); |
114 |
glVertex2f(-0.5f, m-0.5f); |
115 |
glVertex2f(n-0.5f, m-0.5f); |
116 |
glVertex2f(n-0.5f, -0.5f); |
117 |
glEnd(); |
118 |
|
119 |
glPointSize(zoom / (virtual_width*aspect/(float)width)); |
120 |
|
121 |
float x1,y1,x2,y2; |
122 |
world_extents(x1,y1,x2,y2); |
123 |
|
124 |
int r1=(int)floor(y1),r2=(int)floor(y2); |
125 |
int c1=(int)floor(x1),c2=(int)floor(x2); |
126 |
|
127 |
if (std::max(x2-x1,y2-y1) < 16384) |
128 |
{ |
129 |
//std::cout << "drawing partial matrix (" << r1 << ", " << c1 << ") - (" |
130 |
// << r2 << ", " << c2 << ")" << std::endl; |
131 |
|
132 |
draw_partial_matrix(r1,c1,r2,c2); |
133 |
} |
134 |
else if (_m.num_rows < 32768) { |
135 |
//std::cout << "drawing full matrix" << std::endl; |
136 |
// only draw the full matrix if there isn't a very small portion |
137 |
draw_full_matrix(); |
138 |
} |
139 |
else { |
140 |
r1=(std::max)(r1,0); |
141 |
int r2end=(std::min)(r2,m); |
142 |
|
143 |
r1=r1+16384*frame; |
144 |
r2=(std::min)(r1+16384,r2end); |
145 |
//std::cout << "drawing matrix iteratively " << frame << " (" << r1 << ", " << c1 << ") - (" |
146 |
// << r2 << ", " << c2 << ")" << " " << r2end << std::endl; |
147 |
|
148 |
draw_partial_matrix(r1,c1,r2,c2); |
149 |
|
150 |
if (r2 != r2end) { |
151 |
display_finished = false; |
152 |
} |
153 |
} |
154 |
|
155 |
if (data_panel_visible) |
156 |
{ |
157 |
int r = data_cursor.get_y(); |
158 |
int c = data_cursor.get_x(); |
159 |
|
160 |
if (permutation_state == row_permutation || |
161 |
permutation_state == row_column_permutation) { |
162 |
r = irperm[r]; |
163 |
} |
164 |
if (permutation_state == column_permutation || |
165 |
permutation_state == row_column_permutation) { |
166 |
c = icperm[c]; |
167 |
} |
168 |
|
169 |
// workaround for stupid VC++ bug |
170 |
//data_panel.update(r, c, yasmic::value(r, c, |
171 |
// static_cast<const Matrix&>(_m))); |
172 |
data_panel.update(r,c,(float)matrix_value(r,c), |
173 |
row_label(r), column_label(c)); |
174 |
|
175 |
data_cursor.draw(); |
176 |
} |
177 |
} |
178 |
|
179 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
180 |
template <bool partial, class NRMap, class NCMap, class PRMap, class PCMap> |
181 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::draw_matrix(int r1, int c1, int r2, int c2, |
182 |
ValueType min_val, ValueType inv_val_range, float alpha, |
183 |
NRMap nrv, NCMap ncv, PRMap iprm, PCMap pcm) |
184 |
{ |
185 |
int colormap_entry; |
186 |
ValueType v; |
187 |
|
188 |
int m = _m.num_rows; |
189 |
//int n = _m.num_cols; |
190 |
|
191 |
glBegin( GL_POINTS ); |
192 |
{ |
193 |
for (int pi = std::max(0,r1); pi < std::min(r2, m); ++pi) |
194 |
{ |
195 |
// i is the real row in the matrix for the pith row |
196 |
// of the display |
197 |
int i = iprm[pi]; |
198 |
|
199 |
for (IndexType ri = _m.row_offsets[i]; ri < _m.row_offsets[i+1]; ++ri) |
200 |
{ |
201 |
// j is the real column in the matrix for the pjth |
202 |
// column of the display |
203 |
int j = _m.column_indices[ri]; |
204 |
int pj = pcm[j]; |
205 |
|
206 |
// skip all the columns outside |
207 |
if (partial && (pj < c1 || pj > c2)) { |
208 |
continue; |
209 |
} |
210 |
|
211 |
v = _m.values[ri]*nrv[i]*ncv[j]; |
212 |
|
213 |
// scale v to the range [0,1] |
214 |
v = v - min_val; |
215 |
v = v*inv_val_range; |
216 |
|
217 |
if (!colormap_invert) { |
218 |
colormap_entry = (int)(v*(colormap.size-1)); |
219 |
} else { |
220 |
colormap_entry = (int)(v*(colormap.size-1)); |
221 |
colormap_entry=colormap.size-1-colormap_entry; |
222 |
} |
223 |
|
224 |
glColor4f(colormap.map[colormap_entry*3], |
225 |
colormap.map[colormap_entry*3+1], |
226 |
colormap.map[colormap_entry*3+2], |
227 |
alpha); |
228 |
glVertex2f((GLfloat)pj, (GLfloat)pi); |
229 |
} |
230 |
} |
231 |
} |
232 |
glEnd(); |
233 |
} |
234 |
|
235 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
236 |
template <bool partial, class NRMap, class NCMap> |
237 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::draw_matrix_dispatch(int r1, int c1, int r2, int c2, |
238 |
ValueType min_val, ValueType inv_val_range, float alpha, |
239 |
NRMap nrv, NCMap ncv) |
240 |
{ |
241 |
typedef typename cusp::array1d_view< thrust::counting_iterator<ValueType> > CountingView; |
242 |
CountingView counting_view(thrust::counting_iterator<ValueType>(0), |
243 |
thrust::counting_iterator<ValueType>(_m.num_entries)); |
244 |
|
245 |
switch (permutation_state) { |
246 |
case no_permutation: |
247 |
draw_matrix<partial>(r1,c1,r2,c2,min_val,inv_val_range,alpha,nrv,ncv, |
248 |
counting_view,counting_view); |
249 |
break; |
250 |
|
251 |
case row_permutation: |
252 |
draw_matrix<partial>(r1,c1,r2,c2,min_val,inv_val_range,alpha,nrv,ncv, |
253 |
&irperm[0],counting_view); |
254 |
break; |
255 |
|
256 |
case column_permutation: |
257 |
draw_matrix<partial>(r1,c1,r2,c2,min_val,inv_val_range,alpha,nrv,ncv, |
258 |
counting_view,&cperm[0]); |
259 |
break; |
260 |
|
261 |
case row_column_permutation: |
262 |
draw_matrix<partial>(r1,c1,r2,c2,min_val,inv_val_range,alpha,nrv,ncv, |
263 |
&irperm[0],&cperm[0]); |
264 |
break; |
265 |
} |
266 |
} |
267 |
|
268 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
269 |
template <bool partial> |
270 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::draw_matrix_dispatch(int r1, int c1, int r2, int c2) |
271 |
{ |
272 |
ValueType max_val = matrix_stats.max_val; |
273 |
ValueType min_val = matrix_stats.min_val; |
274 |
|
275 |
if (max_val - min_val <= 0) |
276 |
{ |
277 |
// this sets min_val to something reasonable, and |
278 |
// shows the high end of the colormap if the values |
279 |
// are all equal |
280 |
min_val = max_val - 1.0; |
281 |
} |
282 |
ValueType inv_val_range = 1.0/(max_val - min_val); |
283 |
|
284 |
float alpha = alpha_from_zoom(); |
285 |
|
286 |
typedef typename cusp::array1d_view< thrust::constant_iterator<ValueType> > ConstantView; |
287 |
ConstantView constant_view(thrust::constant_iterator<ValueType>(1), |
288 |
thrust::constant_iterator<ValueType>(1) + _m.num_entries); |
289 |
|
290 |
switch (normalization_state) { |
291 |
case no_normalization: |
292 |
draw_matrix_dispatch<partial>(r1,c1,r2,c2,min_val,inv_val_range,alpha, |
293 |
constant_view, constant_view); |
294 |
break; |
295 |
|
296 |
case row_normalization: |
297 |
draw_matrix_dispatch<partial>(r1,c1,r2,c2,0.0,1.0,alpha, |
298 |
&rnorm[0],constant_view); |
299 |
break; |
300 |
|
301 |
case column_normalization: |
302 |
draw_matrix_dispatch<partial>(r1,c1,r2,c2,0.0,1.0,alpha, |
303 |
constant_view,&cnorm[0]); |
304 |
break; |
305 |
|
306 |
case row_column_normalization: |
307 |
draw_matrix_dispatch<partial>(r1,c1,r2,c2,0.0,1.0,alpha,&rnorm[0],&cnorm[0]); |
308 |
break; |
309 |
} |
310 |
} |
311 |
|
312 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
313 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::draw_full_matrix() |
314 |
{ |
315 |
draw_matrix_dispatch<false>(0,0,_m.num_rows,_m.num_cols); |
316 |
} |
317 |
|
318 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
319 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::draw_partial_matrix(int r1, int c1, int r2, int c2) |
320 |
{ |
321 |
draw_matrix_dispatch<true>(r1,c1,r2,c2); |
322 |
} |
323 |
|
324 |
/** |
325 |
* Compute a point_alpha from the current zoom level. |
326 |
* |
327 |
* zoom < 1: alpha = point_alpha |
328 |
* zoom s.t. point_size >= 2.0 => alpha = 1 |
329 |
*/ |
330 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
331 |
float matrix_canvas<IndexType,ValueType,MemorySpace>::alpha_from_zoom() |
332 |
{ |
333 |
float point_size = zoom / (virtual_width*aspect/(float)width); |
334 |
if (zoom < 1) { |
335 |
return (point_alpha); |
336 |
} |
337 |
else if (point_size >= 2.0f) { |
338 |
return (1.0f); |
339 |
} |
340 |
else |
341 |
{ |
342 |
float zoom_1 = 1.0; |
343 |
float zoom_2 = 2.0*(virtual_width*aspect/(float)width); |
344 |
|
345 |
return 1.0f - (zoom_2 - zoom)/(zoom_2 - zoom_1)*(1.0f-point_alpha); |
346 |
} |
347 |
} |
348 |
|
349 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
350 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::reshape(int w, int h) |
351 |
{ |
352 |
super::reshape(w,h); |
353 |
|
354 |
// handle the subwindow... |
355 |
glutSetWindow(data_panel.get_glut_window_id()); |
356 |
if (data_panel_visible && w < 4*p_offset || h < 4*p_offset) |
357 |
{ |
358 |
// if the window is too small, then hide it! |
359 |
hide_data_panel(); |
360 |
} |
361 |
else if (data_panel_visible) |
362 |
{ |
363 |
glutPositionWindow(p_offset, p_offset); |
364 |
glutReshapeWindow(w-2*p_offset, std::min(h/2,p_height)); |
365 |
} |
366 |
|
367 |
glutSetWindow(get_glut_window_id()); |
368 |
|
369 |
/*int x,y,w_glui,h_glui; |
370 |
GLUI_Master.get_viewport_area(&x,&y,&w_glui,&h_glui); |
371 |
if (data_panel_visible) |
372 |
{ |
373 |
//y += panel_height; |
374 |
h_glui -= p_height; |
375 |
} |
376 |
|
377 |
super::reshape(w_glui,h_glui); |
378 |
glViewport(x,y,w_glui,h_glui);*/ |
379 |
} |
380 |
|
381 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
382 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::motion(int x, int y) |
383 |
{ |
384 |
display_finished = true; |
385 |
|
386 |
// rescale the mouse click |
387 |
int move_x = x-mouse_begin_x; |
388 |
int move_y = y-mouse_begin_y; |
389 |
|
390 |
double scaled_x, scaled_y; |
391 |
scaled_x = scale_to_world((float)move_x); |
392 |
scaled_y = scale_to_world((float)move_y); |
393 |
|
394 |
double norm_x=scaled_x, norm_y=scaled_y; |
395 |
norm_x /= aspect; |
396 |
|
397 |
if (data_cursor.scaled_motion(norm_x, norm_y)) |
398 |
{ |
399 |
begin_mouse_click(x,y); |
400 |
} |
401 |
else |
402 |
{ |
403 |
super::motion(x, y); |
404 |
} |
405 |
} |
406 |
|
407 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
408 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::mouse_click(int button, int state, int x, int y) |
409 |
{ |
410 |
if (data_cursor.mouse_click(button, state, x, y)) |
411 |
{ |
412 |
begin_mouse_click(x,y); |
413 |
} |
414 |
else |
415 |
{ |
416 |
super::mouse_click(button, state, x, y); |
417 |
} |
418 |
} |
419 |
|
420 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
421 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::key(unsigned char key, int x, int y) |
422 |
{ |
423 |
switch (key) { |
424 |
case 'o': |
425 |
case 'O': |
426 |
write_svg(); |
427 |
break; |
428 |
} |
429 |
} |
430 |
|
431 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
432 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::special_key(int key, int x, int y) |
433 |
{ |
434 |
switch (key) { |
435 |
case GLUT_KEY_UP: |
436 |
data_cursor.set_position(data_cursor.get_x(),data_cursor.get_y()-1); |
437 |
glutPostRedisplay(); |
438 |
break; |
439 |
|
440 |
case GLUT_KEY_DOWN: |
441 |
data_cursor.set_position(data_cursor.get_x(),data_cursor.get_y()+1); |
442 |
glutPostRedisplay(); |
443 |
break; |
444 |
|
445 |
case GLUT_KEY_LEFT: |
446 |
data_cursor.set_position(data_cursor.get_x()-1,data_cursor.get_y()); |
447 |
glutPostRedisplay(); |
448 |
break; |
449 |
|
450 |
case GLUT_KEY_RIGHT: |
451 |
data_cursor.set_position(data_cursor.get_x()+1,data_cursor.get_y()); |
452 |
glutPostRedisplay(); |
453 |
break; |
454 |
} |
455 |
} |
456 |
|
457 |
|
458 |
/** |
459 |
* This function initializes the window and assures it is |
460 |
* sized correctly, etc. |
461 |
*/ |
462 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
463 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::init_window() |
464 |
{ |
465 |
// make sure we are the current window |
466 |
glutSetWindow(get_glut_window_id()); |
467 |
|
468 |
set_center(_m.num_cols/2, _m.num_rows/2); |
469 |
set_natural_size(_m.num_cols, _m.num_rows); |
470 |
|
471 |
glEnable(GL_BLEND); |
472 |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
473 |
|
474 |
#if !defined (__APPLE__) |
475 |
// POINT_SMOOTHING doesn't work quite right on OS X when I tried it |
476 |
glEnable(GL_POINT_SMOOTH); |
477 |
#endif |
478 |
} |
479 |
|
480 |
/** |
481 |
* This function creates the display list for the matrix. |
482 |
*/ |
483 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
484 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::init_display_list() |
485 |
{ |
486 |
glutSetWindow(get_glut_window_id()); |
487 |
} |
488 |
|
489 |
/* |
490 |
* ================= |
491 |
* matrix functions |
492 |
* ================= |
493 |
*/ |
494 |
|
495 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
496 |
ValueType matrix_canvas<IndexType,ValueType,MemorySpace>::matrix_value( |
497 |
IndexType r, IndexType c) |
498 |
{ |
499 |
int m = _m.num_rows; |
500 |
int n = _m.num_cols; |
501 |
|
502 |
if (r < 0 || r >= m || c < 0 || c >= n) |
503 |
{ |
504 |
return ValueType(0); |
505 |
} |
506 |
|
507 |
IndexType ri,riend; |
508 |
ri = _m.row_offsets[r]; |
509 |
riend = _m.row_offsets[r+1]; |
510 |
|
511 |
while (ri < riend) |
512 |
{ |
513 |
if (c == _m.column_indices[ri]) { |
514 |
return _m.values[ri]; |
515 |
} |
516 |
++ri; |
517 |
} |
518 |
return ValueType(0); |
519 |
} |
520 |
|
521 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
522 |
const std::string& matrix_canvas<IndexType,ValueType,MemorySpace>::row_label(IndexType r) |
523 |
{ |
524 |
if (r >= 0 && r < IndexType(rlabel.size())) { |
525 |
return rlabel[r]; |
526 |
} else { |
527 |
return empty_label; |
528 |
} |
529 |
} |
530 |
|
531 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
532 |
const std::string& matrix_canvas<IndexType,ValueType,MemorySpace>::column_label(IndexType c) |
533 |
{ |
534 |
if (c >= 0 && c < IndexType(clabel.size())) { |
535 |
return clabel[c]; |
536 |
} else { |
537 |
return empty_label; |
538 |
} |
539 |
} |
540 |
|
541 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
542 |
template< typename MatrixType > |
543 |
bool matrix_canvas<IndexType,ValueType,MemorySpace>::load_matrix(const MatrixType& A) |
544 |
{ |
545 |
matrix_loaded = false; |
546 |
|
547 |
_m = A; |
548 |
|
549 |
int m = A.num_rows; |
550 |
int n = A.num_cols; |
551 |
|
552 |
matrix_loaded = true; |
553 |
init_window(); |
554 |
data_cursor.set_matrix_size(_m.num_rows, _m.num_cols); |
555 |
|
556 |
// |
557 |
// compute matrix stats |
558 |
// |
559 |
|
560 |
matrix_stats.max_degree = 0; |
561 |
matrix_stats.min_degree = std::numeric_limits<IndexType>::max(); |
562 |
matrix_stats.max_val = std::numeric_limits<ValueType>::min(); |
563 |
matrix_stats.min_val = std::numeric_limits<ValueType>::max(); |
564 |
|
565 |
rnorm.resize(m); |
566 |
cnorm.resize(n); |
567 |
|
568 |
for (IndexType r = 0; r < m; ++r) |
569 |
{ |
570 |
IndexType deg = _m.row_offsets[r+1] - _m.row_offsets[r]; |
571 |
matrix_stats.max_degree = std::max(matrix_stats.max_degree, deg); |
572 |
matrix_stats.min_degree = std::min(matrix_stats.min_degree, deg); |
573 |
|
574 |
for (IndexType ri = _m.row_offsets[r]; ri < _m.row_offsets[r+1]; ++ri) |
575 |
{ |
576 |
ValueType val = _m.values[ri]; |
577 |
matrix_stats.max_val = std::max(matrix_stats.max_val, val); |
578 |
matrix_stats.min_val = std::min(matrix_stats.min_val, val); |
579 |
|
580 |
rnorm[r] += val*val; |
581 |
cnorm[_m.column_indices[ri]] += val*val; |
582 |
} |
583 |
} |
584 |
for (IndexType r=0; r<m; ++r) { |
585 |
rnorm[r]=1.0/sqrt(rnorm[r]); |
586 |
} |
587 |
for (IndexType r=0; r<n; ++r) { |
588 |
cnorm[r]=1.0/sqrt(cnorm[r]); |
589 |
} |
590 |
|
591 |
return (true); |
592 |
} |
593 |
|
594 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
595 |
bool matrix_canvas<IndexType,ValueType,MemorySpace>::load_permutations(const std::string& rperm_filename, |
596 |
const std::string& cperm_filename) |
597 |
{ |
598 |
/*if (!rperm_filename.empty() && !util::file_exists(rperm_filename)) { |
599 |
std::cerr << rperm_filename << " does not exist." << std::endl; |
600 |
return (false); |
601 |
} |
602 |
|
603 |
if (!cperm_filename.empty() && !util::file_exists(cperm_filename)) { |
604 |
std::cerr << cperm_filename << " does not exist." << std::endl; |
605 |
return (false); |
606 |
} |
607 |
|
608 |
// use all the boost iostreams stuff loaded from the load_crm_matrix.hpp |
609 |
// header file |
610 |
typedef boost::iostreams::filtering_stream< |
611 |
boost::iostreams::input_seekable> |
612 |
filtered_ifstream; |
613 |
|
614 |
if (!rperm_filename.empty()) |
615 |
{ |
616 |
YASMIC_VERBOSE( std::cerr << "reading " << rperm_filename << std::endl; ) |
617 |
filtered_ifstream ios_fifs; |
618 |
ifstream ifs(rperm_filename.c_str()); |
619 |
|
620 |
if (util::gzip_header(ifs)) |
621 |
{ |
622 |
ifs.seekg(0, ios::beg); |
623 |
ios_fifs.push(boost::iostreams::gzip_decompressor()); |
624 |
YASMIC_VERBOSE( std::cerr << "detected gzip" << std::endl; ) |
625 |
} |
626 |
|
627 |
ios_fifs.push(ifs); |
628 |
|
629 |
string line; |
630 |
|
631 |
irperm.resize(_m.nrows); |
632 |
|
633 |
IndexType r; |
634 |
for (r=0; r<_m.nrows && !ios_fifs.eof(); ++r) { |
635 |
IndexType p; |
636 |
ifs >> p; |
637 |
irperm[r]=p; |
638 |
} |
639 |
|
640 |
if (r!=_m.nrows) { |
641 |
std::cerr << rperm_filename << " only contains " << r << " entries, " |
642 |
<< " not " << _m.nrows << std::endl; |
643 |
return (false); |
644 |
} |
645 |
|
646 |
rperm_loaded = true; |
647 |
} |
648 |
|
649 |
if (!cperm_filename.empty()) |
650 |
{ |
651 |
YASMIC_VERBOSE( std::cerr << "reading " << cperm_filename << std::endl; ) |
652 |
filtered_ifstream ios_fifs; |
653 |
ifstream ifs(cperm_filename.c_str()); |
654 |
|
655 |
if (util::gzip_header(ifs)) |
656 |
{ |
657 |
ifs.seekg(0, ios::beg); |
658 |
ios_fifs.push(boost::iostreams::gzip_decompressor()); |
659 |
YASMIC_VERBOSE( std::cerr << "detected gzip" << std::endl; ) |
660 |
} |
661 |
|
662 |
ios_fifs.push(ifs); |
663 |
|
664 |
string line; |
665 |
|
666 |
cperm.resize(_m.ncols); |
667 |
icperm.resize(_m.ncols); |
668 |
|
669 |
IndexType c; |
670 |
for (c=0; c<_m.ncols && !ios_fifs.eof(); ++c) { |
671 |
IndexType p; |
672 |
ifs >> p; |
673 |
icperm[c]=p; |
674 |
cperm[p]=c; |
675 |
} |
676 |
|
677 |
if (c!=_m.ncols) { |
678 |
std::cerr << cperm_filename << " only contains " << c << " entries, " |
679 |
<< " not " << _m.ncols << std::endl; |
680 |
return (false); |
681 |
} |
682 |
|
683 |
cperm_loaded = true; |
684 |
}*/ |
685 |
|
686 |
return (true); |
687 |
} |
688 |
|
689 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
690 |
bool matrix_canvas<IndexType,ValueType,MemorySpace>::load_labels(const std::string& rlabel_filename, |
691 |
const std::string& clabel_filename) |
692 |
{ |
693 |
/*if (!rlabel_filename.empty() && !util::file_exists(rlabel_filename)) { |
694 |
std::cerr << rlabel_filename << " does not exist." << std::endl; |
695 |
return (false); |
696 |
} |
697 |
|
698 |
if (!clabel_filename.empty() && !util::file_exists(clabel_filename)) { |
699 |
std::cerr << clabel_filename << " does not exist." << std::endl; |
700 |
return (false); |
701 |
} |
702 |
|
703 |
// use all the boost iostreams stuff loaded from the load_crm_matrix.hpp |
704 |
// header file |
705 |
typedef boost::iostreams::filtering_stream< |
706 |
boost::iostreams::input_seekable> |
707 |
filtered_ifstream; |
708 |
|
709 |
if (!rlabel_filename.empty()) |
710 |
{ |
711 |
YASMIC_VERBOSE( std::cerr << "reading " << rlabel_filename << std::endl; ) |
712 |
filtered_ifstream ios_fifs; |
713 |
ifstream ifs(rlabel_filename.c_str()); |
714 |
|
715 |
if (util::gzip_header(ifs)) |
716 |
{ |
717 |
ifs.seekg(0, ios::beg); |
718 |
ios_fifs.push(boost::iostreams::gzip_decompressor()); |
719 |
YASMIC_VERBOSE( std::cerr << "detected gzip" << std::endl; ) |
720 |
} |
721 |
|
722 |
ios_fifs.push(ifs); |
723 |
|
724 |
string line; |
725 |
|
726 |
while (!ios_fifs.eof()) { |
727 |
getline(ios_fifs, line); |
728 |
rlabel.push_back(line); |
729 |
} |
730 |
} |
731 |
|
732 |
if (!clabel_filename.empty()) |
733 |
{ |
734 |
YASMIC_VERBOSE( std::cerr << "reading " << clabel_filename << std::endl; ) |
735 |
filtered_ifstream ios_fifs; |
736 |
ifstream ifs(clabel_filename.c_str()); |
737 |
|
738 |
if (util::gzip_header(ifs)) |
739 |
{ |
740 |
ifs.seekg(0, ios::beg); |
741 |
ios_fifs.push(boost::iostreams::gzip_decompressor()); |
742 |
YASMIC_VERBOSE( std::cerr << "detected gzip" << std::endl; ) |
743 |
} |
744 |
|
745 |
ios_fifs.push(ifs); |
746 |
|
747 |
string line; |
748 |
|
749 |
while (!ios_fifs.eof()) { |
750 |
getline(ios_fifs, line); |
751 |
clabel.push_back(line); |
752 |
} |
753 |
}*/ |
754 |
|
755 |
return (true); |
756 |
} |
757 |
|
758 |
/* |
759 |
* ================= |
760 |
* control functions |
761 |
* ================= |
762 |
*/ |
763 |
|
764 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
765 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::show_data_panel() |
766 |
{ |
767 |
glutSetWindow(data_panel.get_glut_window_id()); |
768 |
glutShowWindow(); |
769 |
glutPostRedisplay(); |
770 |
data_panel_visible = true; |
771 |
reshape(width, height); |
772 |
} |
773 |
|
774 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
775 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::hide_data_panel() |
776 |
{ |
777 |
glutSetWindow(data_panel.get_glut_window_id()); |
778 |
glutHideWindow(); |
779 |
data_panel_visible = false; |
780 |
reshape(width, height); |
781 |
} |
782 |
|
783 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
784 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::set_colormap(colormap_state_type c) |
785 |
{ |
786 |
// at the moment, we don't have any support for a user colormap |
787 |
if (c == user_colormap) { |
788 |
c = rainbow_colormap; |
789 |
} |
790 |
switch (c) |
791 |
{ |
792 |
case rainbow_colormap: |
793 |
colormap.map = (float*)rainbow_color_map; |
794 |
colormap.size = sizeof(rainbow_color_map)/sizeof(rainbow_color_map[0]); |
795 |
break; |
796 |
|
797 |
case bone_colormap: |
798 |
colormap.map = (float*)bone_color_map; |
799 |
colormap.size = sizeof(bone_color_map)/sizeof(bone_color_map[0]); |
800 |
break; |
801 |
|
802 |
case spring_colormap: |
803 |
colormap.map = (float*)spring_color_map; |
804 |
colormap.size = sizeof(spring_color_map)/sizeof(spring_color_map[0]); |
805 |
break; |
806 |
|
807 |
default : |
808 |
break; |
809 |
} |
810 |
|
811 |
glutPostRedisplay(); |
812 |
} |
813 |
|
814 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
815 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::set_next_colormap() |
816 |
{ |
817 |
int next = colormap_state+1; |
818 |
if (next == last_colormap) { |
819 |
next = first_colormap; |
820 |
} |
821 |
set_colormap((colormap_state_type)next); |
822 |
} |
823 |
|
824 |
/* |
825 |
* ================= |
826 |
* menu functions |
827 |
* ================= |
828 |
*/ |
829 |
|
830 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
831 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::init_menu() |
832 |
{ |
833 |
int submenu_aspect_ratio = glutCreateMenu(glut_menu); |
834 |
glutAddMenuEntry("1:1",menu_aspect_normal); |
835 |
glutAddMenuEntry("4:1 (Tall)",menu_aspect_tall_41); |
836 |
glutAddMenuEntry("2:1 (Tall)",menu_aspect_tall_21); |
837 |
glutAddMenuEntry("1:2 (Wide)",menu_aspect_wide_12); |
838 |
glutAddMenuEntry("1:4 (Wide)",menu_aspect_wide_14); |
839 |
|
840 |
int submenu_colormap = glutCreateMenu(glut_menu); |
841 |
glutAddMenuEntry("Rainbow",menu_colormap_rainbow); |
842 |
glutAddMenuEntry("Bone",menu_colormap_bone); |
843 |
glutAddMenuEntry("Spring",menu_colormap_spring); |
844 |
glutAddMenuEntry("Invert Colormap",menu_colormap_invert); |
845 |
|
846 |
int submenu_colors = glutCreateMenu(glut_menu); |
847 |
glutAddMenuEntry("White Background",menu_colors_white_bkg); |
848 |
glutAddMenuEntry("Black Background",menu_colors_black_bkg); |
849 |
|
850 |
// create the main menu |
851 |
glutCreateMenu(glut_menu); |
852 |
|
853 |
glutAddMenuEntry("Toggle Cursor", menu_toggle_cursor_id); |
854 |
glutAddSubMenu("Aspect Ratio", submenu_aspect_ratio); |
855 |
glutAddSubMenu("Colormap", submenu_colormap); |
856 |
glutAddSubMenu("Colors", submenu_colors); |
857 |
|
858 |
glutAddMenuEntry("Exit", menu_exit_id); |
859 |
|
860 |
glutAttachMenu(GLUT_RIGHT_BUTTON); |
861 |
} |
862 |
|
863 |
template< typename IndexType, typename ValueType, typename MemorySpace > |
864 |
void matrix_canvas<IndexType,ValueType,MemorySpace>::menu(int value) |
865 |
{ |
866 |
bool update_screen = false; |
867 |
switch (value) |
868 |
{ |
869 |
case menu_file_id: |
870 |
break; |
871 |
|
872 |
case menu_toggle_cursor_id: |
873 |
data_panel_visible ? hide_data_panel() : show_data_panel(); |
874 |
update_screen = true; |
875 |
break; |
876 |
|
877 |
case menu_exit_id: |
878 |
exit(0); |
879 |
break; |
880 |
|
881 |
case menu_aspect_normal: |
882 |
set_aspect(1.0); |
883 |
reshape(width,height); |
884 |
update_screen = true; |
885 |
break; |
886 |
|
887 |
case menu_aspect_wide_12: |
888 |
set_aspect(2.0); |
889 |
reshape(width,height); |
890 |
update_screen = true; |
891 |
break; |
892 |
|
893 |
case menu_aspect_wide_14: |
894 |
set_aspect(4.0); |
895 |
reshape(width,height); |
896 |
update_screen = true; |
897 |
break; |
898 |
|
899 |
case menu_aspect_tall_21: |
900 |
set_aspect(0.5); |
901 |
reshape(width,height); |
902 |
update_screen = true; |
903 |
break; |
904 |
|
905 |
case menu_aspect_tall_41: |
906 |
set_aspect(0.25); |
907 |
reshape(width,height); |
908 |
update_screen = true; |
909 |
break; |
910 |
|
911 |
case menu_colormap_rainbow: |
912 |
set_colormap(rainbow_colormap); |
913 |
break; |
914 |
|
915 |
case menu_colormap_bone: |
916 |
set_colormap(bone_colormap); |
917 |
break; |
918 |
|
919 |
case menu_colormap_spring: |
920 |
set_colormap(spring_colormap); |
921 |
break; |
922 |
|
923 |
case menu_colormap_invert: |
924 |
colormap_invert = !colormap_invert; |
925 |
update_screen = true; |
926 |
break; |
927 |
|
928 |
case menu_colors_white_bkg: |
929 |
set_background_color(1.0f,1.0f,1.0f); |
930 |
data_panel.set_background_color(0.75f,0.75f,0.75f); |
931 |
data_panel.set_text_color(0.0f,0.0f,0.0f); |
932 |
data_panel.set_border_color(0.0f,0.0f,1.0f); |
933 |
set_border_color(0.0f,0.0f,0.0f); |
934 |
data_cursor.set_color(1.0f,0.0f,0.0f); |
935 |
update_screen = true; |
936 |
break; |
937 |
|
938 |
case menu_colors_black_bkg: |
939 |
set_background_color(0.0f,0.0f,0.0f); |
940 |
data_panel.set_background_color(0.25f,0.25f,0.25f); |
941 |
data_panel.set_text_color(1.0f,1.0f,1.0f); |
942 |
data_panel.set_border_color(0.0f,1.0f,0.0f); |
943 |
set_border_color(1.0f,1.0f,1.0f); |
944 |
data_cursor.set_color(1.0f,1.0f,0.0f); |
945 |
update_screen = true; |
946 |
break; |
947 |
|
948 |
} |
949 |
|
950 |
if (update_screen) { |
951 |
display_finished = true; |
952 |
glutPostRedisplay(); |
953 |
} |
954 |
} |
955 |
|
956 |
} // end spy |
957 |
} // end opengl |
958 |
} // end cusp |