"Fossies" - the Fresh Open Source Software Archive 
Member "pfstools-2.2.0/src/pfsview/pfsview_widget.cpp" (12 Aug 2021, 22865 Bytes) of package /linux/privat/pfstools-2.2.0.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "pfsview_widget.cpp" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.1.0_vs_2.2.0.
1 /**
2 * @brief
3 *
4 * This file is a part of PFSTOOLS package.
5 * ----------------------------------------------------------------------
6 * Copyright (C) 2003,2004 Rafal Mantiuk and Grzegorz Krawczyk
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * ----------------------------------------------------------------------
22 *
23 * @author Rafal Mantiuk, <mantiuk@mpi-sb.mpg.de>
24 *
25 * $Id: pfsview_widget.cpp,v 1.26 2014/10/13 09:27:38 rafm Exp $
26 */
27
28 #include <config.h>
29 #include <cmath>
30
31 #include <stdio.h>
32 #include <math.h>
33 #include <pfs.h>
34
35 #include <qmessagebox.h>
36 #include <qcolor.h>
37 #include <qcursor.h>
38 #include <qapplication.h>
39 #include <QMouseEvent>
40 #include <QEvent>
41 #include <QApplication>
42 #include <QDesktopWidget>
43 #include <QList>
44
45 #include <algorithm>
46
47 #include "pfsview_widget.h"
48
49 //#include "pfsglviewwidget.h"
50
51
52 #include <assert.h>
53
54 #define min(x,y) ( (x)<(y) ? (x) : (y) )
55 #define max(x,y) ( (x)>(y) ? (x) : (y) )
56
57
58 #define D65_LUM_R 0.212656f
59 #define D65_LUM_G 0.715158f
60 #define D65_LUM_B 0.072186f
61
62
63 inline float clamp( float val, float min, float max )
64 {
65 if( val < min ) return min;
66 if( val > max ) return max;
67 return val;
68 }
69
70 inline int clamp( int val, int min, int max )
71 {
72 if( val < min ) return min;
73 if( val > max ) return max;
74 return val;
75 }
76
77
78 const char* COLOR_CHANNELS = "Color";
79
80 PFSViewWidgetArea::PFSViewWidgetArea( QWidget *parent ) :
81 QScrollArea( parent )
82 {
83 PFSViewWidget *pfsview = new PFSViewWidget( this );
84 setWidget( pfsview );
85 setWidgetResizable( true );
86
87 setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
88 }
89
90 QSize PFSViewWidgetArea::sizeHint() const
91 {
92 QSize sz = widget()->sizeHint();
93 // printf( "widget: %d %d\n", sz.width(), sz.height() );
94 sz += QSize( frameWidth()*2, frameWidth()*2 );
95 // printf( "area: %d %d\n", sz.width(), sz.height() );
96 return sz;
97 }
98
99
100 PFSViewWidget::PFSViewWidget( QWidget *parent ) :
101 QWidget( parent ), image( NULL ),
102 minValue( 1.f ), maxValue( 100.f ), zoom( 1.f ),
103 mappingMethod( MAP_GAMMA2_2 ), visibleChannel( COLOR_CHANNELS ),
104 negativeTreatment( NEGATIVE_BLACK ), infNaNTreatment( INFNAN_MARK_AS_RED ),
105 updateMappingRequested( true ), clippingMethod(CLIP_SIMPLE)
106 {
107
108 fit_to_content_mode = true;
109 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
110
111
112 setMouseTracking( true );
113 setCursor( QCursor( Qt::CrossCursor ) );
114
115 //name, Qt::WNoAutoErase
116
117 // setResizePolicy( Manual );
118
119 pfsFrame = NULL;
120 workArea[0] = workArea[1] = workArea[2] = NULL;
121
122 selection += QRegion( 10, 10, 100, 100 );
123
124 pointerValue.valid = false;
125
126 }
127
128 PFSViewWidget::~PFSViewWidget()
129 {
130 delete pfsFrame;
131 delete workArea[0];
132 delete workArea[1];
133 delete workArea[2];
134 }
135
136 // ======================= Set current frame ==========================
137
138 void PFSViewWidget::setFrame( pfs::Frame *frame )
139 {
140 pfsFrame = frame;
141 if( frame == NULL ) return;
142
143 // If selected channel not available
144 if( ( visibleChannel == COLOR_CHANNELS && !hasColorChannels( frame ) ) ||
145 ( visibleChannel != COLOR_CHANNELS && frame->getChannel( visibleChannel ) == NULL ) )
146 {
147 // Chose first available channel
148 pfs::ChannelIterator *it = frame->getChannels();
149 if( !it->hasNext() ) // TODO: failover
150 throw new pfs::Exception( "No channels available!" );
151 visibleChannel = it->getNext()->getName();
152 } else if( visibleChannel != COLOR_CHANNELS ) {
153 // Get a new pointer, as the old frame object
154 // can be delete after returning from this method
155 visibleChannel = frame->getChannel( visibleChannel )->getName();
156 }
157
158 if( fit_to_content_mode ) {
159 int desktopWidth, desktopHeight;
160 desktopWidth = QApplication::desktop()->width();
161 desktopHeight = QApplication::desktop()->height();
162 if( frame->getWidth() > desktopWidth ||
163 frame->getHeight() > desktopHeight ) {
164 zoom = min( (float)desktopWidth / (float)frame->getWidth(),
165 (float)desktopHeight / (float)frame->getHeight() );
166 }
167 }
168 updateZoom();
169
170 setPointer();
171 }
172
173 //void PFSViewWidget::drawContents( QPainter * p, int clipx, int clipy, int clipw, int cliph )
174
175 void PFSViewWidget::paintEvent( QPaintEvent *event )
176 {
177 assert( pfsFrame != NULL );
178
179 QRect clip = event->rect();
180 int clipx = clip.x();
181 int clipy = clip.y();
182 int clipw = clip.width();
183 int cliph = clip.height();
184
185
186 if( updateMappingRequested )
187 updateMapping();
188
189 QPainter p( this );
190 // if( image != NULL ) p->drawImage( 0, 0, *image );
191 if( image != NULL ) {
192 p.drawImage( clipx, clipy, *image, clipx, clipy, clipw, cliph );
193
194 //Erase area outside image
195 if( clipx+clipw > image->width() )
196 p.eraseRect( image->width(), 0, clipx+clipw - image->width(), image->height() );
197 if( clipy+cliph > image->height() )
198 p.eraseRect( 0, image->height(), image->width(), clipy+cliph - image->height() );
199 if( clipx+clipw > image->width() && clipy+cliph > image->height() )
200 p.eraseRect( image->width(), image->height(),
201 clipx+clipw - image->width(), clipy+cliph - image->height() );
202
203 }
204
205
206 }
207
208 // ======================= Update ===========================
209
210 static void scaleCopyArray(const pfs::Array2D *from, pfs::Array2D *to)
211 {
212 assert( from->getRows() >= to->getRows() );
213 assert( from->getCols() >= to->getCols() );
214
215 float sx, sy;
216 float dx = (float)from->getCols() / (float)to->getCols();
217 float dy = (float)from->getRows() / (float)to->getRows();
218
219 int x, y, i = 0;
220 for( sy = 0, y = 0; y < to->getRows(); y++, sy += dy ) {
221 for( sx = 0, x = 0; x < to->getCols(); x++, sx += dx ) {
222 (*to)(i++) = (*from)((int)(sx), (int)(sy) );
223 }
224 }
225
226 }
227
228 static void transformImageToWorkArea( pfs::Array2D **workArea, float zoom, bool color,
229 pfs::Array2D *X, pfs::Array2D *Y = NULL, pfs::Array2D *Z = NULL )
230 {
231 int origCols, origRows;
232 origCols = X->getCols();
233 origRows = X->getRows();
234
235 int workCols, workRows;
236 workCols = min( (int)((float)X->getCols() * zoom), X->getCols() );
237 workRows = min( (int)((float)X->getRows() * zoom), X->getRows() );
238
239 int requiredChannels = color ? 3 : 1;
240
241 // Reallocate work area arrays to fit new size
242 {
243 for( int c = 0; c < requiredChannels; c++ ) {
244 if( workArea[c] == NULL || workArea[c]->getCols() != workCols ||
245 workArea[c]->getRows() != workRows ) {
246 if( workArea[c] != NULL ) delete workArea[c];
247 workArea[c] = new pfs::Array2DImpl( workCols, workRows );
248 }
249 }
250 }
251
252 //Copy | rescale & tranform image to work area
253 if( color )
254 {
255 if( workCols == origCols && workRows == origRows ) {
256 copyArray( X, workArea[0] );
257 copyArray( Y, workArea[1] );
258 copyArray( Z, workArea[2] );
259 } else {
260 scaleCopyArray( X, workArea[0] );
261 scaleCopyArray( Y, workArea[1] );
262 scaleCopyArray( Z, workArea[2] );
263 }
264 pfs::transformColorSpace( pfs::CS_XYZ, workArea[0], workArea[1], workArea[2],
265 pfs::CS_RGB, workArea[0], workArea[1], workArea[2] );
266 } else {
267 if( workCols == origCols && workRows == origRows )
268 copyArray( X, workArea[0] );
269 else
270 scaleCopyArray( X, workArea[0] );
271 }
272
273 }
274
275 #define LUTSIZE 256
276
277 inline int binarySearchPixels( float x, const float *lut, const int lutSize )
278 {
279 int l = 0, r = lutSize;
280 while( true ) {
281 int m = (l+r)/2;
282 if( m == l ) break;
283 if( x < lut[m] )
284 r = m;
285 else
286 l = m;
287 }
288 return l;
289 }
290
291 static float getInverseMapping( LumMappingMethod mappingMethod,
292 float v, float minValue, float maxValue )
293 {
294 switch( mappingMethod ) {
295 case MAP_GAMMA1_4:
296 return powf( v, 1.4 )*(maxValue-minValue) + minValue;
297 case MAP_GAMMA1_8:
298 return powf( v, 1.8 )*(maxValue-minValue) + minValue;
299 case MAP_GAMMA2_2:
300 return powf( v, 2.2 )*(maxValue-minValue) + minValue;
301 case MAP_GAMMA2_6:
302 return powf( v, 2.6 )*(maxValue-minValue) + minValue;
303 case MAP_LINEAR:
304 return v*(maxValue-minValue) + minValue;
305 case MAP_LOGARITHMIC:
306 return powf( 10, v * (log10f(maxValue) - log10f(minValue)) + log10f( minValue ) );
307 default:
308 assert(0);
309 return 0;
310 }
311 }
312
313 /**
314 * Copy pixels in work area to QImage using proper clipping and mapping
315 * method. Handle also expansion if image in zoomed in.
316 */
317 static void mapFrameToImage( pfs::Array2D *R, pfs::Array2D *G, pfs::Array2D *B,
318 QImage *img,
319 float minValue, float maxValue,
320 RGBClippingMethod clippingMethod,
321 LumMappingMethod mappingMethod,
322 InfNaNTreatment infNaNTreatment,
323 NegativeTreatment negativeTreatment )
324 {
325 assert( R != NULL );
326 assert( img != NULL );
327 int rows = R->getRows();
328 int cols = R->getCols();
329 bool expand = cols != img->width() || rows != img->height(); // Zoom in
330
331 float imgDeltaRow, imgDeltaCol;
332 if( expand ) {
333 imgDeltaRow = (float)(img->height()) / (float)rows;
334 imgDeltaCol = (float)(img->width()) / (float)cols;
335 } else {
336 imgDeltaRow = imgDeltaCol = 1;
337 }
338
339 bool color = (G != NULL);
340 assert( !color || (color && B != NULL) );
341
342
343 float lutPixFloor[257*2];
344 QRgb lutPixel[257*2];
345 int lutSize;
346 if( !color && ( negativeTreatment == NEGATIVE_GREEN_SCALE ||
347 negativeTreatment == NEGATIVE_ABSOLUTE ) ) { // Handle negative numbers
348 lutSize = 257*2+1;
349 for( int p = 256; p >= 0; p-- ) {
350 float p_left = (float)p/255.f;
351 lutPixFloor[256-p+1] = -getInverseMapping( mappingMethod, p_left, minValue, maxValue );
352 if( p != 0 ) lutPixel[256-p+1] = negativeTreatment == NEGATIVE_GREEN_SCALE ?
353 QColor( 0, p-1, 0 ).rgb() : QColor( p-1, p-1, p-1 ).rgb();
354 }
355 for( int p = 0; p < 257; p++ ) {
356 float p_left = (float)p/255.f;
357 lutPixFloor[257+p+1] = getInverseMapping( mappingMethod, p_left, minValue, maxValue );
358 if( p != 256 ) lutPixel[257+p+1] = QColor( p, p, p ).rgb();
359 }
360
361 if( clippingMethod == CLIP_COLORCODED ) {
362 lutPixel[0] = negativeTreatment == NEGATIVE_GREEN_SCALE ?
363 QColor( 0, 255, 255 ).rgb() : QColor( 255, 255, 0 ).rgb();
364 lutPixel[257] = QColor( 0, 0, 255 ).rgb();
365 lutPixel[257*2-1] = QColor( 255, 255, 0 ).rgb();
366 } else {
367 lutPixel[0] = lutPixel[1];
368 lutPixel[257] = QColor( 0, 0, 0 ).rgb();
369 lutPixel[257*2-1] = QColor( 255, 255, 255 ).rgb();
370 }
371
372 } else { // clip negative numbers
373 int neg_offset = ((!color && negativeTreatment == NEGATIVE_MARK_AS_RED) ? 1 : 0);
374 lutSize = 257+1 + neg_offset; // +1 - for lower bound
375 for( int p = 1+neg_offset; p <= LUTSIZE+1; p++ ) {
376 float p_left = ((float)p - 1.f - (float)neg_offset)/255.f; // Should be -1.5f, but we don't want negative nums
377 lutPixFloor[p] = getInverseMapping( mappingMethod, p_left, minValue, maxValue );
378 if( !color && p < LUTSIZE+1+neg_offset ) lutPixel[p] = QColor( p-1-neg_offset, p-1-neg_offset, p-1-neg_offset ).rgb();
379 // printf( "p = %d\tl = %g\n", p, lookupTable[p] );
380 }
381 if( clippingMethod == CLIP_COLORCODED ) {
382 lutPixel[neg_offset] = QColor( 0, 0, 255 ).rgb();
383 lutPixel[LUTSIZE+1+neg_offset] = QColor( 255, 255, 0 ).rgb();
384 } else {
385 lutPixel[neg_offset] = QColor( 0, 0, 0 ).rgb();
386 lutPixel[LUTSIZE+1+neg_offset] = QColor( 255, 255, 255 ).rgb();
387 }
388 if( negativeTreatment == NEGATIVE_MARK_AS_RED && !color) {
389 lutPixFloor[1] = 0;
390 lutPixel[0] = QColor( 255, 0, 0 ).rgb();
391 }
392 }
393
394 // bool once = true;
395
396 // #pragma omp parallel for private (index)
397 #pragma omp parallel for
398 for( int r = 0; r < rows; r++ ) {
399 float imgRow, imgCol;
400 int index = r*cols;
401 imgRow = (float)r * imgDeltaRow;
402 QRgb* line = (QRgb*)img->scanLine( (int)imgRow );
403 imgCol = 0;
404 for( int c = 0; c < cols; c++, index++, imgCol += imgDeltaCol ) {
405 QRgb pixel;
406 if( color ) {
407 // Color channels
408 int pr, pg, pb;
409 pr = binarySearchPixels( (*R)(index), lutPixFloor, lutSize );
410 pg = binarySearchPixels( (*G)(index), lutPixFloor, lutSize );
411 pb = binarySearchPixels( (*B)(index), lutPixFloor, lutSize );
412
413 // Clipping
414 if( clippingMethod == CLIP_COLORCODED ) {
415 if( pr == 0 || pg == 0 || pb == 0 )
416 pixel = lutPixel[0];
417 else if( pr == lutSize-1 || pg == lutSize-1 || pb == lutSize-1 )
418 pixel = lutPixel[LUTSIZE+1];
419 else
420 pixel = QColor( pr-1, pg-1, pb-1 ).rgb();
421 } else if( clippingMethod == CLIP_KEEP_BRI_HUE ) {
422 if( pr == lutSize-1 || pg == lutSize-1 || pb == lutSize-1 ||
423 pr == 0 || pg == 0 || pb == 0 ) {
424 float p[3];
425 p[0] = (*R)(index); p[1] = (*G)(index); p[2] = (*B)(index);
426 float gray = (p[0]+p[1]+p[2])/3.f;
427 // float gray = D65_LUM_R*p[0]+D65_LUM_G*p[1]+D65_LUM_B*p[2];
428 float t;
429
430 if( gray >= maxValue ) {
431 pixel = QColor( 255, 255, 255 ).rgb();
432 } else if( gray <= minValue ) {
433 pixel = QColor( 0, 0, 0 ).rgb();
434 } else {
435 int i;
436 for( i = 0; i < 3; i++ ) {
437 t = (maxValue - p[i])/(gray - p[i]);
438 if( t >= 0 && t <= 1 ) {
439 break;
440 }
441 t = (minValue - p[i])/(gray - p[i]);
442 if( t >= 0 && t <= 1 ) {
443 break;
444 }
445 }
446
447 if( i == 3 )
448 pixel = QColor( 255, 255, 255 ).rgb();
449 else {
450 for( int i = 0; i < 3; i++ )
451 p[i] = gray*t + p[i]*(1-t);
452
453 // if( once ) {
454 // printf( "min = %g max = %g\n", minValue, maxValue );
455 // printf( "r = %g g = %g b = %g; t = %g\n", p[0], p[1], p[2], t );
456 // once = false;
457 // }
458
459 pr = binarySearchPixels( p[0], lutPixFloor, lutSize );
460 pg = binarySearchPixels( p[1], lutPixFloor, lutSize );
461 pb = binarySearchPixels( p[2], lutPixFloor, lutSize );
462 pixel = QColor( clamp( pr-1, 0, 255 ),
463 clamp( pg-1, 0, 255 ),
464 clamp( pb-1, 0, 255 ) ).rgb();
465 }
466 }
467 } else {
468 pixel = QColor( clamp( pr-1, 0, 255 ),
469 clamp( pg-1, 0, 255 ),
470 clamp( pb-1, 0, 255 ) ).rgb();
471 }
472 } else {
473 pixel = QColor( clamp( pr-1, 0, 255 ),
474 clamp( pg-1, 0, 255 ),
475 clamp( pb-1, 0, 255 ) ).rgb();
476 }
477 if( infNaNTreatment == INFNAN_MARK_AS_RED ) {
478 if( !std::isfinite( (*R)(index) ) || !std::isfinite( (*G)(index) ) || !std::isfinite( (*B)(index) ) )
479 { // x is NaN or Inf
480 pixel = QColor( 255, 0, 0 ).rgb();
481 }
482 }
483 if( negativeTreatment == NEGATIVE_MARK_AS_RED ) {
484 if( (*R)(index)<0 || (*G)(index)<0 || (*B)(index)<0 )
485 { // x is negative
486 pixel = QColor( 255, 0, 0 ).rgb();
487 }
488 }
489
490 } else {
491 // Single channel
492 int p = binarySearchPixels( (*R)(index), lutPixFloor, lutSize );
493 pixel = lutPixel[p];
494 if( infNaNTreatment == INFNAN_MARK_AS_RED && (p == 0 || p == LUTSIZE+1))
495 if( !std::isfinite( (*R)(index) ) ) { // x is NaN or Inf
496 pixel = QColor( 255, 0, 0 ).rgb();
497 }
498
499 }
500
501 line[(int)imgCol] = pixel;
502
503 if( expand ) {
504 for( int ec = (int)imgCol + 1; ec < (int)(imgCol+imgDeltaCol); ec++ ) {
505 line[ec] = pixel;
506 }
507 }
508
509 }
510
511 if( expand ) {
512 for( int er = (int)(imgRow + 1); er < (int)(imgRow + imgDeltaRow); er++ ) {
513 QRgb* eLine = (QRgb*)img->scanLine( er );
514 memcpy( eLine, line, sizeof( QRgb )*img->width() );
515 }
516
517 }
518
519 }
520
521 }
522
523 void PFSViewWidget::postUpdateMapping()
524 {
525 updateMappingRequested = true;
526
527 update( 0, 0, image->width(), image->height() );
528 //updateContents( 0, 0, image->width(), image->height() );
529 }
530
531
532 void PFSViewWidget::updateMapping()
533 {
534 assert( image != NULL );
535
536 QApplication::setOverrideCursor( Qt::WaitCursor );
537
538 if( visibleChannel == COLOR_CHANNELS ) {
539
540 assert( workArea[0] != NULL && workArea[1] != NULL && workArea[2] != NULL );
541 mapFrameToImage( workArea[0], workArea[1], workArea[2], image,
542 minValue, maxValue, clippingMethod, mappingMethod,
543 infNaNTreatment, negativeTreatment );
544
545 } else {
546
547 assert( workArea[0] != NULL );
548 mapFrameToImage( workArea[0], NULL, NULL, image,
549 minValue, maxValue, clippingMethod, mappingMethod,
550 infNaNTreatment, negativeTreatment );
551 }
552 updateMappingRequested = false;
553
554 QApplication::restoreOverrideCursor();
555 }
556
557 void PFSViewWidget::updateZoom()
558 {
559 assert( pfsFrame != NULL );
560
561 QApplication::setOverrideCursor( Qt::WaitCursor );
562
563 if( visibleChannel == COLOR_CHANNELS ) {
564 pfs::Channel *X, *Y, *Z;
565 pfsFrame->getXYZChannels( X, Y, Z );
566 transformImageToWorkArea( workArea, zoom, true, X, Y, Z );
567 } else {
568 pfs::Channel *X = pfsFrame->getChannel( visibleChannel );
569 transformImageToWorkArea( workArea, zoom, false, X );
570 }
571
572 int zoomedWidth = max( workArea[0]->getCols(), (int)((float)(pfsFrame->getWidth())*zoom) );
573 int zoomedHeight = max( workArea[0]->getRows(), (int)((float)(pfsFrame->getHeight())*zoom) );
574
575 if( image != NULL ) delete image;
576 image = new QImage( zoomedWidth, zoomedHeight, QImage::Format_RGB32 );
577 assert( image != NULL );
578
579 postUpdateMapping();
580
581 resize( zoomedWidth, zoomedHeight );
582
583 // resizeContents( zoomedWidth, zoomedHeight );
584 // updateContents( 0, 0, zoomedWidth, zoomedHeight );
585 update( 0, 0, zoomedWidth, zoomedHeight );
586
587 QApplication::restoreOverrideCursor();
588 }
589
590 QSize PFSViewWidget::sizeHint() const
591 {
592 if( pfsFrame != NULL )
593 return QSize( (int)((float)pfsFrame->getWidth()*zoom), (int)((float)pfsFrame->getHeight()*zoom) );
594
595 // return QSize( (int)((float)pfsFrame->getWidth()*zoom) + 2 * frameWidth(), (int)((float)pfsFrame->getHeight()*zoom) + 2 * frameWidth() );
596
597 // return QSize( pfsFrame->getWidth() + 2 * frameWidth(), pfsFrame->getHeight() + 2 * frameWidth() );
598 else return QWidget::sizeHint();
599 }
600
601 // ======================= Events ===========================
602
603 void PFSViewWidget::setRGBClippingMethod( QAction *action )
604 {
605 clippingMethod = (RGBClippingMethod)action->data().toUInt();
606 postUpdateMapping();
607 }
608
609 void PFSViewWidget::setInfNaNTreatment( QAction *action )
610 {
611 infNaNTreatment = (InfNaNTreatment)action->data().toUInt();
612 postUpdateMapping();
613 }
614
615 void PFSViewWidget::setNegativeTreatment( QAction *action )
616 {
617 negativeTreatment = (NegativeTreatment)action->data().toUInt();
618 postUpdateMapping();
619 }
620
621 void PFSViewWidget::setLumMappingMethod( int method )
622 {
623 mappingMethod = (LumMappingMethod)method;
624 postUpdateMapping();
625 }
626
627
628
629 void PFSViewWidget::zoomIn()
630 {
631 if( zoom >= 10 ) return;
632 zoom *= 1.25f;
633 fit_to_content_mode = false;
634 updateZoom();
635 }
636
637
638 void PFSViewWidget::zoomOut()
639 {
640 if( zoom <= 0.05 ) return;
641 zoom *= 0.8f;
642 fit_to_content_mode = false;
643 updateZoom();
644 }
645
646 void PFSViewWidget::zoomOriginal()
647 {
648 zoom = 1;
649 fit_to_content_mode = false;
650 updateZoom();
651 }
652
653 void PFSViewWidget::setRangeWindow( float min, float max )
654 {
655 minValue = min;
656 maxValue = max;
657 postUpdateMapping();
658 }
659
660
661 // ===================== Mouse interaction =========================
662
663 void PFSViewWidget::mouseMoveEvent( QMouseEvent *mouseEvent )
664 {
665 assert( pfsFrame != NULL );
666
667 setPointer( (int)((float)mouseEvent->x() / zoom),
668 (int)((float)mouseEvent->y() / zoom) );
669 }
670
671 void PFSViewWidget::setPointer( int x, int y )
672 {
673 assert( pfsFrame != NULL );
674
675 if( x >= 0 ) {
676 pointerValue.x = x;
677 pointerValue.y = y;
678 }
679
680 if( pointerValue.x >= 0 && pointerValue.x < pfsFrame->getWidth() &&
681 pointerValue.y >= 0 && pointerValue.y < pfsFrame->getHeight() ) {
682
683 if( visibleChannel == COLOR_CHANNELS ) {
684
685 pfs::Channel *X, *Y, *Z;
686 pfsFrame->getXYZChannels( X, Y, Z );
687
688 pointerValue.value[0] = (*X)( pointerValue.x, pointerValue.y );
689 pointerValue.value[1] = (*Y)( pointerValue.x, pointerValue.y );
690 pointerValue.value[2] = (*Z)( pointerValue.x, pointerValue.y );
691
692 pointerValue.valuesUsed = 3;
693 pointerValue.valid = true;
694
695 } else {
696
697 pfs::Channel *X;
698 X = pfsFrame->getChannel( visibleChannel );
699
700 pointerValue.value[0] = (*X)( pointerValue.x, pointerValue.y );
701
702 pointerValue.valuesUsed = 1;
703 pointerValue.valid = true;
704
705 }
706
707 updatePointerValue();
708
709 } else {
710 pointerValue.valid = false;
711 updatePointerValue();
712 }
713
714
715 }
716
717 void PFSViewWidget::leaveEvent ( QEvent * )
718 {
719 pointerValue.valid = false;
720 updatePointerValue();
721 }
722
723 const PointerValue &PFSViewWidget::getPointerValue()
724 {
725 return pointerValue;
726 }
727
728
729 // ===================== Data access =========================
730
731
732 const pfs::Array2D *PFSViewWidget::getPrimaryChannel()
733 {
734 assert( pfsFrame != NULL );
735 if( visibleChannel == COLOR_CHANNELS ) {
736 pfs::Channel *X, *Y, *Z;
737 pfsFrame->getXYZChannels( X, Y, Z );
738 return Y;
739 } else {
740 return pfsFrame->getChannel( visibleChannel );
741 }
742
743 }
744
745 const QList<const char*> PFSViewWidget::getChannels()
746 {
747 assert( pfsFrame != NULL );
748
749 QList<const char*> chArray;
750
751 pfs::ChannelIterator *it = pfsFrame->getChannels();
752 it = pfsFrame->getChannels();
753 while( it->hasNext() )
754 {
755 pfs::Channel *ch = it->getNext();
756 chArray.push_back(ch->getName());
757 }
758
759 return chArray;
760 }
761
762 void PFSViewWidget::setVisibleChannel( const char *channelName )
763 {
764 visibleChannelName = channelName;
765
766 visibleChannel = channelName != NULL ? (const char*)visibleChannelName : COLOR_CHANNELS;
767
768 updateZoom();
769 setPointer();
770 }
771
772 const char *PFSViewWidget::getVisibleChannel()
773 {
774 return visibleChannel;
775 }
776
777 bool PFSViewWidget::hasColorChannels( pfs::Frame *frame )
778 {
779 if( frame == NULL ) frame = pfsFrame;
780 assert( frame != NULL );
781 pfs::Channel *X, *Y, *Z;
782 frame->getXYZChannels( X, Y, Z );
783 return ( X != NULL );
784 }
785