NorMIT-nav  2023.01.05-dev+develop.0da12
An IGT application
cxTransferFunctionAlphaWidget.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 <limits.h>
15 #include <vtkImageData.h>
16 #include <vtkPointData.h>
17 #include <vtkImageAccumulate.h>
18 #include <QPainter>
19 #include <QPen>
20 #include <QColor>
21 #include <QBrush>
22 #include <QMouseEvent>
23 #include "cxImageTF3D.h"
24 #include "cxImageTFData.h"
25 #include "cxLogger.h"
26 #include "cxUtilHelpers.h"
27 #include "cxTypeConversions.h"
28 #include "vtkDataArray.h"
29 #include "cxReporter.h"
30 
31 namespace cx
32 {
34  BaseWidget(parent, "transfer_function_alpha_widget", "Alpha Transfer Function"),
35  mBorder(5),
36  mReadOnly(false)
37 {
38  this->setToolTip("Set the alpha part of a transfer function");
39  this->setFocusPolicy(Qt::StrongFocus);
40 
42  connect(mActiveImageProxy.get(), SIGNAL(transferFunctionsChanged()), this, SLOT(activeImageTransferFunctionsChangedSlot()));
43 
45 }
47 {}
48 
50 {
51  if (( mImage == image )&&( mImageTF==tfData ))
52  return;
53 
54  mImage = image;
55  mImageTF = tfData;
56  this->update();
57 }
58 
60 {
61  mReadOnly = readOnly;
62 }
63 
65 {
66  this->update();
67 }
68 
70 {
71  this->setMouseTracking(true);
72 }
73 
75 {
76  this->setMouseTracking(false);
77 }
78 
80 {
81  if(mReadOnly)
82  return;
83  QWidget::mousePressEvent(event);
84 
85  if(event->button() == Qt::LeftButton)
86  {
87  mSelectedAlphaPoint = this->selectPoint(event->pos());
88  }
89  else if(event->button() == Qt::RightButton)
90  {
91  this->toggleSelectedPoint(event->pos());
92  }
93 
94  this->update();
95 }
96 
98 {
99  if(mReadOnly)
100  return;
101  QWidget::mouseReleaseEvent(event);
102 // mCurrentAlphaPoint.reset();
103 }
104 
106 {
107  if (!mImage)
108  return;
109 
110  this->updateTooltip(event->pos());
111  if(mReadOnly) //Only show tool tip if readOnly
112  return;
113 
114  QWidget::mouseMoveEvent(event);
115 
116  if(event->buttons() == Qt::LeftButton)
117  {
118  this->moveCurrentAlphaPoint(this->getCurrentAlphaPoint(event->pos()));
119  this->update();
120  }
121 }
122 
124 {
126  {
127  int shift = 0;
128  int alphaShift = 0;
129  if (event->key()==Qt::Key_Left)
130  shift = -1;
131  if (event->key()==Qt::Key_Right)
132  shift = +1;
133  if (event->key()==Qt::Key_Down)
134  alphaShift = -1;
135  if (event->key()==Qt::Key_Up)
136  alphaShift = +1;
137 
138  if ((shift!=0) || (alphaShift!=0))
139  {
140  AlphaPoint newPoint = mSelectedAlphaPoint;
141  newPoint.position += shift;
142  newPoint.value += alphaShift;
143  this->moveCurrentAlphaPoint(newPoint);
145  this->update();
146  return;
147  }
148  }
149 
150  QWidget::keyPressEvent(event);
151 }
152 
154 {
155  AlphaPoint selected = this->selectPoint(pos);
156  if (!selected.isValid())
157  selected = this->getCurrentAlphaPoint(pos);
158  this->updateTooltip(selected);
159  this->update();
160 }
161 
163 {
164  QString tip = QString("alpha(%1)=%2").arg(point.position).arg(double(point.value)/255, 0, 'f', 2);
165  this->setToolTip(tip);
166  reporter()->sendVolatile(tip);
167 }
168 
169 
171 {
172  QWidget::paintEvent(event);
173  QPainter painter(this);
174  this->clearBackground(painter);
175 
176  if (!mImage)
177  return;
178 
179  this->paintHistogram(painter);
180  this->paintOpacityGraph(painter);
181 }
182 
183 void TransferFunctionAlphaWidget::clearBackground(QPainter& painter)
184 {
185  // Fill with white global background color and grey plot area background color
186  const QBrush frameBrush = QBrush(QColor(170, 170, 170));
187  const QBrush backgroundBrush = QBrush(QColor(200, 200, 200));
188  painter.fillRect(this->mFullArea, frameBrush);
189  painter.fillRect(this->mPlotArea, backgroundBrush);
190 
191 }
192 
194 {
195  QPen pointPen, pointLinePen;
196  pointPen.setColor(QColor(0, 0, 150));
197  pointLinePen.setColor(QColor(150, 100, 100));
198 
199  // Go through each point and draw squares and lines
200  IntIntMap opacityMap = mImageTF->getOpacityMap();
201 
202  QPoint lastScreenPoint;
203  this->mPointRects.clear();
204  for (IntIntMap::iterator opPoint = opacityMap.begin();
205  opPoint != opacityMap.end();
206  ++opPoint)
207  {
208  // Get the screen (plot) position of this point
209  AlphaPoint pt(opPoint->first, opPoint->second);
210  QPoint screenPoint = this->alpha2screen(pt);
211 
212  // draw line from left edge to first point:
213  if (opPoint==opacityMap.begin())
214  {
215  lastScreenPoint = QPoint(mPlotArea.left(), screenPoint.y());
216  }
217 
218  // Draw line from previous point
219  painter.setPen(pointLinePen);
220  painter.drawLine(lastScreenPoint, screenPoint);
221 
222  // Draw the rectangle
223  QRect pointRect(screenPoint.x() - mBorder, screenPoint.y() - mBorder,
224  mBorder*2, mBorder*2);
225  if (opPoint->first==mSelectedAlphaPoint.position)
226  {
227  pointPen.setWidth(2);
228  painter.setPen(pointPen);
229  }
230  else
231  {
232  pointPen.setWidth(1);
233  painter.setPen(pointPen);
234  }
235  painter.drawRect(pointRect);
236  this->mPointRects[opPoint->first] = pointRect;
237 
238  // Store the point
239  lastScreenPoint = screenPoint;
240  }
241 
242  // draw a line from the last point to the right end
243  QPoint screenPoint(mPlotArea.right(), lastScreenPoint.y());
244  painter.setPen(pointLinePen);
245  painter.drawLine(lastScreenPoint, screenPoint);
246 
247 }
248 
250 {
251  QPoint screenPoint = QPoint(
252  static_cast<int>(mPlotArea.left() + mPlotArea.width() *
253  (pt.position - mImage->getMin()) /
254  static_cast<double>(mImage->getRange())),
255  static_cast<int>(mPlotArea.bottom() - mPlotArea.height() *
256  pt.value /
257  static_cast<double>(mImage->getMaxAlphaValue())) );
258  return screenPoint;
259 }
260 
262 {
263  // Draw histogram
264  // with log compression
265 
266  vtkImageAccumulatePtr histogram = mImage->getHistogram();
267  int histogramSize = histogram->GetComponentExtent()[1] -
268  histogram->GetComponentExtent()[0];
269 
270  painter.setPen(QColor(140, 140, 210));
271 
272  double numElementsInBinWithMostElements = log(histogram->GetOutput()->GetPointData()->GetScalars()->GetRange()[1]+1);
273  double barHeightMult = (this->height() - mBorder*2) / numElementsInBinWithMostElements;
274 
275  double posMult = (this->width() - mBorder*2) / double(histogramSize);
276  for (int i = mImage->getMin(); i <= mImage->getMax(); i++)
277  {
278  int x = int(std::lround(((i- mImage->getMin()) * posMult))); //Offset with min value
279  int y = int(std::lround(log(double(static_cast<int*>(histogram->GetOutput()->GetScalarPointer(i - mImage->getMin(), 0, 0))[0]+1)) * barHeightMult));
280  if (y > 0)
281  {
282  painter.drawLine(x + mBorder, height() - mBorder,
283  x + mBorder, height() - mBorder - y);
284  }
285  }
286 }
287 
288 
290 {
291  QWidget::resizeEvent(evt);
292 
293  // Calculate areas
294  this->mFullArea = QRect(0, 0, width(), height());
295  this->mPlotArea = QRect(mBorder, mBorder,
296  width() - mBorder*2, height() - mBorder*2);
297 }
298 
300 {
301  std::map<int, QRect>::iterator it = mPointRects.begin();
302  for(;it != mPointRects.end(); ++it)
303  {
304  if (it->second.contains(pos))
305  {
306  AlphaPoint retval;
307  retval.position = it->first;
308  IntIntMap opactiyMap = mImageTF->getOpacityMap();
309  if (opactiyMap.find(retval.position) != opactiyMap.end())
310  retval.value = opactiyMap.find(retval.position)->second;
311  return retval;
312  }
313  }
314 
315  return AlphaPoint();
316 }
317 
319 {
320  if (mPointRects.begin()->first == intensity)
321  return true;
322  if (mPointRects.rbegin()->first == intensity)
323  return true;
324  return false;
325 }
326 
328 {
329  AlphaPoint point;
330 
331  double dposition = mImage->getMin() + mImage->getRange() * double(pos.x() - mPlotArea.left()) / mPlotArea.width();
332  double dvalue = mImage->getMaxAlphaValue() * double(mPlotArea.bottom() - pos.y())/mPlotArea.height();
333  point.position = int(std::lround(dposition));
334  point.value = int(std::lround(dvalue));
335 
336  point.position = constrainValue(point.position, mImage->getMin(), mImage->getMax());
337  point.value = constrainValue(point.value, 0, mImage->getMaxAlphaValue());
338 
339  return point;
340 }
341 
343 {
344  if(!mImage)
345  return;
346  mSelectedAlphaPoint = this->selectPoint(pos);
348  {
349  // Outside any of the rectangles
350  AlphaPoint point = getCurrentAlphaPoint(pos);
351  mImageTF->addAlphaPoint(point.position,point.value);
352  mSelectedAlphaPoint = this->selectPoint(pos);
353  }
354  else if(!this->isEndpoint(mSelectedAlphaPoint.position))
355  {
356  // Inside one of the rectangles
358  mImageTF->removeAlphaPoint(mSelectedAlphaPoint.position);
360  }
361 
362  this->update();
363 }
364 
366 {
368  return;
369 
370  newAlphaPoint.value = constrainValue(newAlphaPoint.value, 0, 255);
371 
372  std::pair<int,int> range = this->findAllowedMoveRangeAroundAlphaPoint(mSelectedAlphaPoint.position);
373  newAlphaPoint.position = constrainValue(newAlphaPoint.position, range.first, range.second);
374 
375  mImageTF->moveAlphaPoint(mSelectedAlphaPoint.position, newAlphaPoint.position, newAlphaPoint.value);
376 
377  mSelectedAlphaPoint = newAlphaPoint;
378  this->update();
379 }
380 
381 std::pair<int,int> TransferFunctionAlphaWidget::findAllowedMoveRangeAroundAlphaPoint(int selectedPointIntensity)
382 {
383  // constrain new point intensity between the two neigbours
384  IntIntMap opacityMap = mImageTF->getOpacityMap();
385  IntIntMap::iterator pointIterator = opacityMap.find(selectedPointIntensity);
386 
387  std::pair<int,int> range(mImage->getMin(), mImage->getMax());
388  if (pointIterator!=opacityMap.begin())
389  {
390  IntIntMap::iterator prevPointIterator = pointIterator;
391  --prevPointIterator;
392  range.first = std::max(range.first, prevPointIterator->first + 1);
393  }
394 
395  IntIntMap::iterator nextPointIterator = pointIterator;
396  ++nextPointIterator;
397  if (nextPointIterator!=opacityMap.end())
398  {
399  range.second = std::min(range.second, nextPointIterator->first - 1);
400  }
401 
402  return range;
403 }
404 
405 
406 }//namespace cx
cx::TransferFunctionAlphaWidget::moveCurrentAlphaPoint
void moveCurrentAlphaPoint(AlphaPoint newAlphaPoint)
Definition: cxTransferFunctionAlphaWidget.cpp:365
cx::TransferFunctionAlphaWidget::resizeEvent
virtual void resizeEvent(QResizeEvent *evt)
Reimplemented from superclass.
Definition: cxTransferFunctionAlphaWidget.cpp:289
cxLogger.h
cx::TransferFunctionAlphaWidget::mReadOnly
bool mReadOnly
Is class readOnly? Eg no mouse interaction possible.
Definition: cxTransferFunctionAlphaWidget.h:104
cx::TransferFunctionAlphaWidget::AlphaPoint::isValid
bool isValid()
Definition: cxTransferFunctionAlphaWidget.h:70
cx::TransferFunctionAlphaWidget::findAllowedMoveRangeAroundAlphaPoint
std::pair< int, int > findAllowedMoveRangeAroundAlphaPoint(int selectedPointIntensity)
Definition: cxTransferFunctionAlphaWidget.cpp:381
cx
Namespace for all CustusX production code.
Definition: cx_dev_group_definitions.h:13
cx::TransferFunctionAlphaWidget::~TransferFunctionAlphaWidget
virtual ~TransferFunctionAlphaWidget()
Definition: cxTransferFunctionAlphaWidget.cpp:46
cx::BaseWidget
Interface for QWidget which handles widgets uniformly for the system.
Definition: cxBaseWidget.h:88
cx::TransferFunctionAlphaWidget::mImage
ImagePtr mImage
Definition: cxTransferFunctionAlphaWidget.h:110
cx::ImageTFDataPtr
boost::shared_ptr< class ImageTFData > ImageTFDataPtr
Definition: cxForwardDeclarations.h:52
cx::ActiveImageProxy::New
static ActiveImageProxyPtr New(ActiveDataPtr activeData)
Definition: cxActiveImageProxy.h:44
cx::TransferFunctionAlphaWidget::getCurrentAlphaPoint
AlphaPoint getCurrentAlphaPoint(QPoint pos)
Get aplha point based on mCurrentClickX and mCurrentClickY.
Definition: cxTransferFunctionAlphaWidget.cpp:327
cx::TransferFunctionAlphaWidget::alpha2screen
QPoint alpha2screen(AlphaPoint pt) const
Definition: cxTransferFunctionAlphaWidget.cpp:249
cxUtilHelpers.h
cxReporter.h
cx::reporter
ReporterPtr reporter()
Definition: cxReporter.cpp:36
cx::TransferFunctionAlphaWidget::AlphaPoint::position
int position
Definition: cxTransferFunctionAlphaWidget.h:55
cx::TransferFunctionAlphaWidget::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionAlphaWidget.cpp:105
cx::TransferFunctionAlphaWidget::mousePressEvent
virtual void mousePressEvent(QMouseEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionAlphaWidget.cpp:79
cx::TransferFunctionAlphaWidget::mActiveImageProxy
ActiveImageProxyPtr mActiveImageProxy
Definition: cxTransferFunctionAlphaWidget.h:112
cx::TransferFunctionAlphaWidget::AlphaPoint::value
int value
Definition: cxTransferFunctionAlphaWidget.h:56
cx::TransferFunctionAlphaWidget::mBorder
int mBorder
The size of the border around the transferfunction. The size of the rectangles are mBorder * 2.
Definition: cxTransferFunctionAlphaWidget.h:103
cx::TransferFunctionAlphaWidget::paintHistogram
void paintHistogram(QPainter &painter)
Definition: cxTransferFunctionAlphaWidget.cpp:261
cx::TransferFunctionAlphaWidget::toggleSelectedPoint
void toggleSelectedPoint(QPoint pos)
Turn a transfer function point on or off (depending on it is on or not)
Definition: cxTransferFunctionAlphaWidget.cpp:342
cx::TransferFunctionAlphaWidget::mSelectedAlphaPoint
AlphaPoint mSelectedAlphaPoint
The current alpha point.
Definition: cxTransferFunctionAlphaWidget.h:107
cx::TransferFunctionAlphaWidget::paintEvent
virtual void paintEvent(QPaintEvent *event)
Reimplemented from superclass. Paints the transferfunction GUI.
Definition: cxTransferFunctionAlphaWidget.cpp:170
cx::TransferFunctionAlphaWidget::keyPressEvent
virtual void keyPressEvent(QKeyEvent *event)
Definition: cxTransferFunctionAlphaWidget.cpp:123
cx::TransferFunctionAlphaWidget::isEndpoint
bool isEndpoint(int intensity) const
Definition: cxTransferFunctionAlphaWidget.cpp:318
cx::TransferFunctionAlphaWidget::mPlotArea
QRect mPlotArea
The plot area.
Definition: cxTransferFunctionAlphaWidget.h:102
vtkImageAccumulatePtr
vtkSmartPointer< class vtkImageAccumulate > vtkImageAccumulatePtr
Definition: vtkForwardDeclarations.h:63
cx::TransferFunctionAlphaWidget::updateTooltip
void updateTooltip(QPoint pos)
Definition: cxTransferFunctionAlphaWidget.cpp:153
cxTypeConversions.h
cx::TransferFunctionAlphaWidget::activeImageTransferFunctionsChangedSlot
void activeImageTransferFunctionsChangedSlot()
Acts when the image's transfer function is changed.
Definition: cxTransferFunctionAlphaWidget.cpp:64
cxImageTFData.h
cx::ImagePtr
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
cx::TransferFunctionAlphaWidget::selectPoint
AlphaPoint selectPoint(QPoint pos)
Definition: cxTransferFunctionAlphaWidget.cpp:299
cx::IntIntMap
std::map< int, int > IntIntMap
Definition: cxImage.h:35
cx::TransferFunctionAlphaWidget::setData
void setData(ImagePtr image, ImageTFDataPtr tfData)
Definition: cxTransferFunctionAlphaWidget.cpp:49
cx::TransferFunctionAlphaWidget::leaveEvent
virtual void leaveEvent(QEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionAlphaWidget.cpp:74
cx::constrainValue
double constrainValue(double val, double min, double max)
Definition: cxUtilHelpers.cpp:28
cx::TransferFunctionAlphaWidget::enterEvent
virtual void enterEvent(QEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionAlphaWidget.cpp:69
cx::TransferFunctionAlphaWidget::setReadOnly
void setReadOnly(bool readOnly)
Set class readonly: Disable mouse interaction.
Definition: cxTransferFunctionAlphaWidget.cpp:59
cx::TransferFunctionAlphaWidget::AlphaPoint
Definition: cxTransferFunctionAlphaWidget.h:53
cx::TransferFunctionAlphaWidget::AlphaPoint::reset
void reset()
Definition: cxTransferFunctionAlphaWidget.h:65
cx::TransferFunctionAlphaWidget::TransferFunctionAlphaWidget
TransferFunctionAlphaWidget(ActiveDataPtr activeData, QWidget *parent)
Definition: cxTransferFunctionAlphaWidget.cpp:33
cx::ActiveDataPtr
boost::shared_ptr< class ActiveData > ActiveDataPtr
Definition: cxColorWidget.h:21
cx::TransferFunctionAlphaWidget::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *event)
Reimplemented from superclass.
Definition: cxTransferFunctionAlphaWidget.cpp:97
cxTransferFunctionAlphaWidget.h
cxImageTF3D.h
cx::TransferFunctionAlphaWidget::mImageTF
ImageTFDataPtr mImageTF
Definition: cxTransferFunctionAlphaWidget.h:111
cx::TransferFunctionAlphaWidget::mPointRects
std::map< int, QRect > mPointRects
Cache with all point rectangles.
Definition: cxTransferFunctionAlphaWidget.h:106
cx::TransferFunctionAlphaWidget::paintOpacityGraph
void paintOpacityGraph(QPainter &painter)
Definition: cxTransferFunctionAlphaWidget.cpp:193
cx::TransferFunctionAlphaWidget::mFullArea
QRect mFullArea
The full widget area.
Definition: cxTransferFunctionAlphaWidget.h:101