NorMIT-nav  2023.01.05-dev+develop.0da12
An IGT application
cxTransferFunctionColorWidget.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
13 
14 #include <vtkColorTransferFunction.h>
15 
16 #include <limits.h>
17 #include <QPainter>
18 #include <QPen>
19 #include <QColor>
20 #include <QMouseEvent>
21 #include <QColorDialog>
22 #include <QMenu>
23 #include <QTimer>
24 #include "cxImageTF3D.h"
25 #include "cxImageTFData.h"
26 #include "cxUtilHelpers.h"
27 #include "cxImageLUT2D.h"
28 #include "cxLogger.h"
29 #include "cxTypeConversions.h"
30 #include "cxReporter.h"
31 
32 namespace cx
33 {
35  BaseWidget(parent, "transfer_function_color_widget", "Color Transfer Function"),
36  mBorder(5),
37  mCurrentClickPos(INT_MIN,INT_MIN)
38 {
39  this->setToolTip("Set the color part of a transfer function");
40  this->setFocusPolicy(Qt::StrongFocus);
42  connect(mActiveImageProxy.get(), SIGNAL(transferFunctionsChanged()), this, SLOT(activeImageTransferFunctionsChangedSlot()));
43 
45 
46  // Create actions
47  mCustomColorAction = new QAction(tr("Custom color..."), this);
48  mRemoveColorAction = new QAction(tr("Remove point"), this);
49 
50  connect(mCustomColorAction, SIGNAL(triggered(bool)), this, SLOT(setColorSlot()));
51  connect(mRemoveColorAction, SIGNAL(triggered()), this, SLOT(removeColorSlot()));
52 }
53 
55 {}
56 
58 {
59  this->setMouseTracking(true);
60 }
61 
63 {
64  this->setMouseTracking(false);
65 }
66 
67 
69 {
70  if (( mImage == image )&&( mImageTF==tfData ))
71  return;
72 
73  mImage = image;
74  mImageTF = tfData;
75  this->update();
76 }
77 
79 {
80  this->update();
81 }
82 
84 {
85  QWidget::mousePressEvent(event);
86  mCurrentClickPos = event->pos();
87 
88  if(event->button() == Qt::LeftButton)
89  {
91  this->update();
92  }
93 }
94 
96 {
97  QWidget::mouseReleaseEvent(event);
98  //we no longer need these values
99  //mSelectedPoint.reset();
100 }
101 
103 {
104  QWidget::mouseMoveEvent(event);
105 
106  if(event->buttons() == Qt::LeftButton)
107  {
108  // Update current screen point for use in moveCurrentAlphaPoint
109  mCurrentClickPos = event->pos();
110 // this->moveCurrentPoint();
112  }
113 
114  this->updateTooltip(event->pos());
115 }
116 
118 {
119  ColorPoint selected = this->selectPoint(pos);
120  if (!selected.isValid())
121  selected = this->getCurrentColorPoint(pos.x());
122  this->updateTooltip(selected);
123  this->update();
124 }
125 
127 {
128  QString tip = QString("color(%1)=(%2)").arg(point.intensity).arg(color2string(point.value));
129 // std::cout << "updated to " << tip << std::endl;
130  this->setToolTip(tip);
131  reporter()->sendVolatile(tip);
132 // this->setStatusTip(tip);
133 }
134 
135 
137 {
138  if (mSelectedPoint.isValid())
139  {
140  int shift = 0;
141  if (event->key()==Qt::Key_Left)
142  shift = -1;
143  if (event->key()==Qt::Key_Right)
144  shift = +1;
145 
146  if (shift!=0)
147  {
148  ColorPoint newPoint = mSelectedPoint;
149  newPoint.intensity += shift;
150  this->moveSelectedPointTo(newPoint);
152  return;
153  }
154  }
155 
156  QWidget::keyPressEvent(event);
157 }
158 
160 {
161  // Get the screen (plot) position of this point
162  int retval =
163  static_cast<int>(mPlotArea.left() + mPlotArea.width() *
164  (intensity - mImage->getMin()) /
165  static_cast<double>(mImage->getRange()));
166  return retval;
167 }
168 
170 {
171  double i = mImage->getMin() + mImage->getRange() * double(screenX - mPlotArea.left()) /(mPlotArea.width()-1);
172  int retval = int(std::lround(i));
173  return retval;
174 }
175 
177 {
178  // Don't do anything before we have an image
179  if (!mImage)
180  return;
181  QWidget::paintEvent(event);
182 
183  QPainter painter(this);
184 
185  // Fill with white background color and grey plot area background color
186  painter.fillRect(this->mFullArea, QColor(170, 170, 170));
187  painter.fillRect(this->mPlotArea, QColor(200, 200, 200));
188 
189  this->paintColorBar(painter);
190  this->paintColorPointsAndGenerateCache(painter);
191 }
192 
194 {
195  // Draw color-background
196 
197  // Use vtkColorTransferFunction for interpolation
198  vtkColorTransferFunctionPtr trFunc = mImageTF->generateColorTF();
199  long imin = std::lround(mImageTF->getLevel() - mImageTF->getWindow()/2);
200  long imax = std::lround(mImageTF->getLevel() + mImageTF->getWindow()/2);
201 
202  for (int x = this->mPlotArea.left(); x <= this->mPlotArea.right(); ++x)
203  {
204  int intensity = screenX2imageIntensity(x);
205  double* rgb = trFunc->GetColor(intensity);
206  painter.setPen(QColor::fromRgbF(rgb[0], rgb[1], rgb[2]));
207 
208  if (( imin <= intensity )&&( intensity <= imax ))
209  {
210  painter.drawLine(x, mPlotArea.top(), x, mPlotArea.bottom());
211  }
212  else
213  {
214  int areaHeight = mPlotArea.bottom() - mPlotArea.top();
215  int halfAreaTop = mPlotArea.top() + areaHeight / 4;
216  int halfAreaBottom = mPlotArea.bottom() - areaHeight / 4;
217  painter.drawLine(x, halfAreaTop, x, halfAreaBottom);
218  }
219  }
220 }
221 
223 {
224  // Go through each point and draw squares
225  ColorMap colorMap = mImageTF->getColorMap();
226  this->mPointRects.clear();
227  for (ColorMap::iterator colorPoint = colorMap.begin(); colorPoint != colorMap.end(); ++colorPoint)
228  {
229  // Get the screen (plot) position of this point
230  int screenX = this->imageIntensity2screenX(colorPoint->first);
231  // Draw the rectangle
232  QRect pointRect(screenX - mBorder, mFullArea.top(),
233  mBorder*2, mFullArea.height());
234 
235  if (colorPoint->first == mSelectedPoint.intensity)
236  {
237  QPen pen;
238  pen.setWidth(2);
239  painter.setPen(pen);
240  }
241  else
242  {
243  QPen pen;
244  painter.setPen(pen);
245  }
246 
247  painter.drawRect(pointRect);
248  this->mPointRects[colorPoint->first] = pointRect;
249  }
250 }
251 
253 {
254  QWidget::resizeEvent(evt);
255 
256  // Calculate areas
257  this->mFullArea = QRect(0, 0, width(), height());
258  this->mPlotArea = QRect(mBorder, mBorder,
259  width() - mBorder*2, height() - mBorder*2);
260 }
261 
263 {
264  std::map<int, QRect>::const_iterator it = mPointRects.begin();
265  for(;it != mPointRects.end(); ++it)
266  {
267  if (it->second.contains(pos))
268  {
269  ColorPoint retval;
270  retval.intensity = it->first;
271  ColorMap colorMap = mImageTF->getColorMap();
272  if (colorMap.find(retval.intensity) != colorMap.end())
273  retval.value = colorMap.find(retval.intensity)->second;
274  return retval;
275  }
276  }
277  return ColorPoint();
278 }
279 
281 {
282  if (mPointRects.begin()->first == intensity)
283  return true;
284  if (mPointRects.rbegin()->first == intensity)
285  return true;
286  return false;
287 }
288 
289 void TransferFunctionColorWidget::contextMenuEvent(QContextMenuEvent *event)
290 {
291  QMenu menu;
292  menu.addAction(mCustomColorAction);
293 
295 
296  if (mSelectedPoint.isValid() && !this->isEndpoint(mSelectedPoint.intensity))
297  {
298  menu.addSeparator();
299  menu.addAction(mRemoveColorAction);
300  }
301  this->update();
302 
303  menu.exec(event->globalPos());
304 }
305 
307 {
308  return this->getCurrentColorPoint(mCurrentClickPos.x());
309 }
310 
312 {
313  ColorPoint point;
314  if(!mImage)
315  return point;
316  point.intensity = screenX2imageIntensity(clickX);
317  point.intensity = constrainValue(point.intensity, mImage->getMin(), mImage->getMax());
318 
319  vtkColorTransferFunctionPtr trFunc = mImageTF->generateColorTF();
320 
321  double* rgb = trFunc->GetColor(point.intensity);
322  point.value = QColor::fromRgbF(rgb[0], rgb[1], rgb[2]);
323  return point;
324 }
325 
326 //void TransferFunctionColorWidget::moveCurrentPoint()
327 //{
328 // if(!mSelectedPoint.isValid())
329 // return;
330 
331 // std::pair<int,int> range = this->findAllowedMoveRangeAroundColorPoint(mSelectedPoint.intensity);
332 
333 // ColorPoint newColorPoint = this->getCurrentColorPoint();
334 // newColorPoint.value = mSelectedPoint.value;
335 // newColorPoint.intensity = constrainValue(newColorPoint.intensity, range.first, range.second);
336 
337 // mImageTF->moveColorPoint(mSelectedPoint.intensity, newColorPoint.intensity, newColorPoint.value);
338 // mSelectedPoint = newColorPoint;
339 // this->update();
340 //}
341 //void TransferFunctionColorWidget::moveCurrentPoint()
342 //{
343 // this->moveCurrentPoint(this->getCurrentColorPoint());
344 //}
345 
347 {
348  if(!mSelectedPoint.isValid())
349  return;
350 
351  std::pair<int,int> range = this->findAllowedMoveRangeAroundColorPoint(mSelectedPoint.intensity);
352 
353 // ColorPoint newColorPoint = this->getCurrentColorPoint();
354  newPoint.value = mSelectedPoint.value;
355  newPoint.intensity = constrainValue(newPoint.intensity, range.first, range.second);
356 
357  mImageTF->moveColorPoint(mSelectedPoint.intensity, newPoint.intensity, newPoint.value);
358  mSelectedPoint = newPoint;
359  this->update();
360 }
361 
362 std::pair<int,int> TransferFunctionColorWidget::findAllowedMoveRangeAroundColorPoint(int selectedPointIntensity)
363 {
364  // constrain new point intensity between the two neigbours
365  ColorMap colorMap = mImageTF->getColorMap();
366  ColorMap::iterator pointIterator = colorMap.find(selectedPointIntensity);
367 
368  std::pair<int,int> range(mImage->getMin(), mImage->getMax());
369  if (pointIterator!=colorMap.begin())
370  {
371  ColorMap::iterator prevPointIterator = pointIterator;
372  --prevPointIterator;
373  range.first = std::max(range.first, prevPointIterator->first + 1);
374  }
375 
376  ColorMap::iterator nextPointIterator = pointIterator;
377  ++nextPointIterator;
378  if (nextPointIterator!=colorMap.end())
379  {
380  range.second = std::min(range.second, nextPointIterator->first - 1);
381  }
382 
383  return range;
384 }
385 
387 {
388 // setColorSlotDelayed(); // crashed sporadically
389  QTimer::singleShot(1, this, SLOT(setColorSlotDelayed()));
390 }
391 
393 {
394  ColorPoint newPoint = mSelectedPoint;
395  if (!newPoint.isValid())
396  newPoint = getCurrentColorPoint();
397 
398  QColor result = QColorDialog::getColor( newPoint.value, this);
399 
400  if (result.isValid() && (result!=newPoint.value))
401  {
402  mImageTF->addColorPoint(newPoint.intensity, result);
403  }
404  this->update();
405 }
406 
408 {
409  if(!this->mSelectedPoint.isValid())
410  return;
411 
412  mImageTF->removeColorPoint(this->mSelectedPoint.intensity);
413 
414  this->update();
415 }
416 
417 }//namespace cx
cxLogger.h
cx::TransferFunctionColorWidget::ColorPoint
Definition: cxTransferFunctionColorWidget.h:56
cx::TransferFunctionColorWidget::moveSelectedPointTo
void moveSelectedPointTo(ColorPoint newPoint)
Definition: cxTransferFunctionColorWidget.cpp:346
cx::TransferFunctionColorWidget::mImageTF
ImageTFDataPtr mImageTF
Definition: cxTransferFunctionColorWidget.h:94
cx::TransferFunctionColorWidget::mousePressEvent
virtual void mousePressEvent(QMouseEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionColorWidget.cpp:83
cx
Namespace for all CustusX production code.
Definition: cx_dev_group_definitions.h:13
cx::TransferFunctionColorWidget::mCurrentClickPos
QPoint mCurrentClickPos
Definition: cxTransferFunctionColorWidget.h:84
cx::TransferFunctionColorWidget::mFullArea
QRect mFullArea
The full widget area.
Definition: cxTransferFunctionColorWidget.h:77
cx::BaseWidget
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:88
cx::ImageTFDataPtr
boost::shared_ptr< class ImageTFData > ImageTFDataPtr
Definition: cxForwardDeclarations.h:52
cx::TransferFunctionColorWidget::activeImageTransferFunctionsChangedSlot
void activeImageTransferFunctionsChangedSlot()
Acts when the image's transfer function is changed.
Definition: cxTransferFunctionColorWidget.cpp:78
cx::TransferFunctionColorWidget::mPointRects
std::map< int, QRect > mPointRects
Cache with all point rectangles
Definition: cxTransferFunctionColorWidget.h:81
cx::TransferFunctionColorWidget::ColorPoint::reset
void reset()
Definition: cxTransferFunctionColorWidget.h:61
cx::ActiveImageProxy::New
static ActiveImageProxyPtr New(ActiveDataPtr activeData)
Definition: cxActiveImageProxy.h:44
cx::TransferFunctionColorWidget::setColorSlot
void setColorSlot()
Definition: cxTransferFunctionColorWidget.cpp:386
cx::TransferFunctionColorWidget::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionColorWidget.cpp:102
cx::TransferFunctionColorWidget::screenX2imageIntensity
int screenX2imageIntensity(int screenX)
Define a recommended size.
Definition: cxTransferFunctionColorWidget.cpp:169
cxUtilHelpers.h
cxReporter.h
cx::reporter
ReporterPtr reporter()
Definition: cxReporter.cpp:36
cx::TransferFunctionColorWidget::leaveEvent
virtual void leaveEvent(QEvent *event)
Definition: cxTransferFunctionColorWidget.cpp:62
cx::TransferFunctionColorWidget::mPlotArea
QRect mPlotArea
The plot area.
Definition: cxTransferFunctionColorWidget.h:78
cx::ColorMap
std::map< int, QColor > ColorMap
Definition: cxImage.h:36
color2string
QString color2string(QColor color)
Definition: cxTypeConversions.cpp:52
cx::TransferFunctionColorWidget::ColorPoint::isValid
bool isValid()
Definition: cxTransferFunctionColorWidget.h:66
cx::TransferFunctionColorWidget::paintEvent
virtual void paintEvent(QPaintEvent *event)
Reimplemented from superclass. Paints the transferfunction GUI.
Definition: cxTransferFunctionColorWidget.cpp:176
cx::TransferFunctionColorWidget::isEndpoint
bool isEndpoint(int intensity) const
Definition: cxTransferFunctionColorWidget.cpp:280
cx::TransferFunctionColorWidget::setData
void setData(ImagePtr image, ImageTFDataPtr tfData)
Definition: cxTransferFunctionColorWidget.cpp:68
cx::TransferFunctionColorWidget::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionColorWidget.cpp:95
cx::TransferFunctionColorWidget::setColorSlotDelayed
void setColorSlotDelayed()
Definition: cxTransferFunctionColorWidget.cpp:392
cx::TransferFunctionColorWidget::mRemoveColorAction
QAction * mRemoveColorAction
Action for removing a color.
Definition: cxTransferFunctionColorWidget.h:75
cx::TransferFunctionColorWidget::mCustomColorAction
QAction * mCustomColorAction
Action for choosing custom color.
Definition: cxTransferFunctionColorWidget.h:74
cx::TransferFunctionColorWidget::mSelectedPoint
ColorPoint mSelectedPoint
The currently selected point.
Definition: cxTransferFunctionColorWidget.h:82
cxTypeConversions.h
cx::TransferFunctionColorWidget::~TransferFunctionColorWidget
virtual ~TransferFunctionColorWidget()
Definition: cxTransferFunctionColorWidget.cpp:54
cx::TransferFunctionColorWidget::enterEvent
virtual void enterEvent(QEvent *event)
Definition: cxTransferFunctionColorWidget.cpp:57
cxImageTFData.h
cx::ImagePtr
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
cx::TransferFunctionColorWidget::mActiveImageProxy
ActiveImageProxyPtr mActiveImageProxy
Definition: cxTransferFunctionColorWidget.h:95
cx::TransferFunctionColorWidget::removeColorSlot
void removeColorSlot()
Definition: cxTransferFunctionColorWidget.cpp:407
cx::constrainValue
double constrainValue(double val, double min, double max)
Definition: cxUtilHelpers.cpp:28
vtkColorTransferFunctionPtr
vtkSmartPointer< class vtkColorTransferFunction > vtkColorTransferFunctionPtr
Definition: vtkForwardDeclarations.h:44
cx::TransferFunctionColorWidget::mImage
ImagePtr mImage
Definition: cxTransferFunctionColorWidget.h:93
cx::TransferFunctionColorWidget::TransferFunctionColorWidget
TransferFunctionColorWidget(ActiveDataPtr activeData, QWidget *parent)
Definition: cxTransferFunctionColorWidget.cpp:34
cxTransferFunctionColorWidget.h
cx::TransferFunctionColorWidget::resizeEvent
virtual void resizeEvent(QResizeEvent *evt)
Reimplemented from superclass.
Definition: cxTransferFunctionColorWidget.cpp:252
cx::TransferFunctionColorWidget::contextMenuEvent
void contextMenuEvent(QContextMenuEvent *event)
Decides what happens when you rightclick in a view.
Definition: cxTransferFunctionColorWidget.cpp:289
cx::TransferFunctionColorWidget::keyPressEvent
virtual void keyPressEvent(QKeyEvent *event)
Definition: cxTransferFunctionColorWidget.cpp:136
cx::TransferFunctionColorWidget::findAllowedMoveRangeAroundColorPoint
std::pair< int, int > findAllowedMoveRangeAroundColorPoint(int selectedPointIntensity)
Definition: cxTransferFunctionColorWidget.cpp:362
cx::TransferFunctionColorWidget::getCurrentColorPoint
ColorPoint getCurrentColorPoint()
Calculate the color point (position and color) based on clicked x coordinate.
Definition: cxTransferFunctionColorWidget.cpp:306
cx::ActiveDataPtr
boost::shared_ptr< class ActiveData > ActiveDataPtr
Definition: cxColorWidget.h:21
cxImageTF3D.h
cx::TransferFunctionColorWidget::mBorder
int mBorder
The size of the border around the transferfunction. The size of the rectangles are mBorder * 2.
Definition: cxTransferFunctionColorWidget.h:79
cxImageLUT2D.h
cx::TransferFunctionColorWidget::ColorPoint::intensity
int intensity
Definition: cxTransferFunctionColorWidget.h:58
cx::TransferFunctionColorWidget::ColorPoint::value
QColor value
Definition: cxTransferFunctionColorWidget.h:59
cx::TransferFunctionColorWidget::selectPoint
ColorPoint selectPoint(QPoint pos) const
Definition: cxTransferFunctionColorWidget.cpp:262
cx::TransferFunctionColorWidget::paintColorBar
void paintColorBar(QPainter &painter)
Definition: cxTransferFunctionColorWidget.cpp:193
cx::TransferFunctionColorWidget::updateTooltip
void updateTooltip(QPoint pos)
Definition: cxTransferFunctionColorWidget.cpp:117
cx::TransferFunctionColorWidget::paintColorPointsAndGenerateCache
void paintColorPointsAndGenerateCache(QPainter &painter)
Definition: cxTransferFunctionColorWidget.cpp:222
cx::TransferFunctionColorWidget::imageIntensity2screenX
int imageIntensity2screenX(int intensity)
Definition: cxTransferFunctionColorWidget.cpp:159