fw4spl
SrcLib/core/fwData/src/fwData/TransferFunction.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwData/TransferFunction.hpp"
8 
9 #include <fwData/Exception.hpp>
10 #include <fwData/registry/macros.hpp>
11 
12 #include <fwCom/Signal.hxx>
13 
14 #include <fwTools/Type.hpp>
15 
16 fwDataRegisterMacro( ::fwData::TransferFunction );
17 
18 namespace fwData
19 {
20 
21 //------------------------------------------------------------------------------
22 
23 const std::string TransferFunction::s_DEFAULT_TF_NAME = "CT-GreyLevel";
24 
25 const ::fwCom::Signals::SignalKeyType TransferFunction::s_POINTS_MODIFIED_SIG = "pointsModified";
26 const ::fwCom::Signals::SignalKeyType TransferFunction::s_WINDOWING_MODIFIED_SIG = "windowingModified";
27 
28 //------------------------------------------------------------------------------
29 
31 {
32  newSignal< PointsModifiedSignalType >(s_POINTS_MODIFIED_SIG);
33  newSignal< WindowingModifiedSignalType >(s_WINDOWING_MODIFIED_SIG);
34 
35  this->initTF();
36 }
37 
38 //------------------------------------------------------------------------------
39 
40 void TransferFunction::initTF()
41 {
42  m_level = 0;
43  m_window = 100;
44 
45  m_name = "";
46 
47  m_interpolationMode = TransferFunction::LINEAR;
48  m_isClamped = true;
49 
50  m_tfData.clear();
51 }
52 
53 //------------------------------------------------------------------------------
54 
55 fwData::TransferFunction::sptr TransferFunction::createDefaultTF()
56 {
57  TransferFunction::sptr tf = TransferFunction::New();
58 
59  tf->setName(TransferFunction::s_DEFAULT_TF_NAME);
60  tf->addTFColor(0.0, TFColor());
61  tf->addTFColor(1.0, TFColor(1.0, 1.0, 1.0, 1.0));
62  tf->setIsClamped(false);
63  tf->setWindow( 500. );
64  tf->setLevel( 50. );
65  return tf;
66 }
67 
68 //------------------------------------------------------------------------------
69 
71 {
72 }
73 
74 //------------------------------------------------------------------------------
75 
76 TransferFunction::TFValueVectorType TransferFunction::getTFValues() const
77 {
78  TFValueVectorType values;
79  values.reserve(m_tfData.size());
80  std::transform( m_tfData.begin(), m_tfData.end(),
81  std::back_inserter(values),
82  std::bind(&TFDataType::value_type::first, std::placeholders::_1) );
83  return values;
84 }
85 
86 //------------------------------------------------------------------------------
87 
88 TransferFunction::TFValueVectorType TransferFunction::getScaledValues() const
89 {
90  TFValueVectorType values;
91  values.reserve(m_tfData.size());
92  TFValuePairType minMax = this->getMinMaxTFValues();
93  TFValuePairType windowMinMax = this->getWLMinMax();
94 
95  const double scale = m_window / (minMax.second - minMax.first);
96 
97  for(const TFDataType::value_type& data : m_tfData)
98  {
99  const double value = (data.first - minMax.first) * scale + windowMinMax.first;
100  values.push_back(value);
101  }
102 
103  return values;
104 }
105 
106 //------------------------------------------------------------------------------
107 
108 TransferFunction::TFValuePairType
110 {
111  SLM_ASSERT("It must have at least one value.", m_tfData.size() >= 1);
112  TFValuePairType minMax;
113  minMax.first = m_tfData.begin()->first;
114  minMax.second = (m_tfData.rbegin())->first;
115  return minMax;
116 }
117 
118 //------------------------------------------------------------------------------
119 
120 TransferFunction::TFValuePairType
122 {
123  TFValuePairType minMax;
124  const double halfWindow = m_window/2.;
125  minMax.first = m_level - halfWindow;
126  minMax.second = m_level + halfWindow;
127  return minMax;
128 }
129 
130 //------------------------------------------------------------------------------
131 
132 void TransferFunction::setWLMinMax(const TFValuePairType& minMax)
133 {
134  m_window = minMax.second - minMax.first;
135  const double halfWindow = m_window/2.;
136  m_level = halfWindow + minMax.first;
137 }
138 
139 //------------------------------------------------------------------------------
140 
141 TransferFunction::TFValueType TransferFunction::getNearestValue( TFValueType value ) const
142 {
143  OSLM_ASSERT("It must have at least one value.", m_tfData.size() >= 1);
144  const std::pair<double, double> minMax = ::fwTools::Type::s_DOUBLE.minMax<double>();
145  double previousValue = minMax.first;
146  double nextValue = minMax.second;
147 
148  TFValueType val;
149  for(const TFDataType::value_type& data : m_tfData)
150  {
151  if(value < data.first )
152  {
153  nextValue = data.first;
154  break;
155  }
156  else
157  {
158  previousValue = data.first;
159  }
160  }
161  if(previousValue == minMax.first)
162  {
163  val = nextValue;
164  }
165  else if(nextValue == minMax.second)
166  {
167  val = previousValue;
168  }
169  else
170  {
171  if((value - previousValue) < (nextValue - value))
172  {
173  val = previousValue;
174  }
175  else
176  {
177  val = nextValue;
178  }
179  }
180  return val;
181 }
182 
183 //------------------------------------------------------------------------------
184 
185 const TransferFunction::TFDataType& TransferFunction::getTFData() const
186 {
187  return m_tfData;
188 }
189 
190 //------------------------------------------------------------------------------
191 
192 void TransferFunction::setTFData( const TFDataType& tfData )
193 {
194  m_tfData = tfData;
195 }
196 
197 //------------------------------------------------------------------------------
198 
199 void TransferFunction::addTFColor( TFValueType value, const TFColor& color )
200 {
201  m_tfData[value] = color;
202 }
203 
204 //------------------------------------------------------------------------------
205 void TransferFunction::eraseTFValue( TFValueType value)
206 {
207  m_tfData.erase(value);
208 }
209 
210 //------------------------------------------------------------------------------
212 {
213  m_tfData.clear();
214 }
215 //------------------------------------------------------------------------------
216 
217 TransferFunction::TFColorVectorType TransferFunction::getTFColors() const
218 {
219  TFColorVectorType colors;
220  std::transform( m_tfData.begin(), m_tfData.end(),
221  std::back_inserter(colors),
222  std::bind(&TFDataType::value_type::second, std::placeholders::_1) );
223  return colors;
224 }
225 
226 //------------------------------------------------------------------------------
227 
229 {
230  OSLM_ASSERT("It must have at least one value.", m_tfData.size() >= 1);
231 
232  const double min = std::numeric_limits<double>::min();
233  const double max = std::numeric_limits<double>::max();
234 
235  double previousValue = min;
236  double nextValue = max;
237 
238  const TFColor blackColor(0.0, 0.0, 0.0, 0.0);
239  TFColor color;
240  TFColor previousColor = blackColor;
241  TFColor nextColor = blackColor;
242 
243  for(const TFDataType::value_type& data : m_tfData)
244  {
245  if(value < data.first )
246  {
247  nextValue = data.first;
248  nextColor = data.second;
249  break;
250  }
251  else
252  {
253  previousValue = data.first;
254  previousColor = data.second;
255  }
256  }
257  if(previousValue == min)
258  {
259  if(m_isClamped)
260  {
261  color = blackColor;
262  }
263  else
264  {
265  color = nextColor;
266  }
267  }
268  else if(nextValue == max)
269  {
270  if(m_isClamped && (value != previousValue))
271  {
272  color = blackColor;
273  }
274  else
275  {
276  color = previousColor;
277  }
278  }
279  else
280  {
281  if((value - previousValue) < (nextValue - value))
282  {
283  color = previousColor;
284  }
285  else
286  {
287  color = nextColor;
288  }
289  }
290 
291  return color;
292 }
293 
294 //------------------------------------------------------------------------------
295 
297 {
298  OSLM_ASSERT("It must have at least one value.", m_tfData.size() >= 1);
299 
300  const double min = std::numeric_limits<double>::min();
301  const double max = std::numeric_limits<double>::max();
302  double previousValue = min;
303  double nextValue = max;
304 
305  const TFColor blackColor(0.0, 0.0, 0.0, 0.0);
306  TFColor color;
307  TFColor previousColor = blackColor;
308  TFColor nextColor = blackColor;
309 
310  for(const TFDataType::value_type& data : m_tfData)
311  {
312  if(value < data.first )
313  {
314  nextValue = data.first;
315  nextColor = data.second;
316  break;
317  }
318  else
319  {
320  previousValue = data.first;
321  previousColor = data.second;
322  }
323  }
324  if(previousValue == min)
325  {
326  if(m_isClamped)
327  {
328  color = blackColor;
329  }
330  else
331  {
332  color = nextColor;
333  }
334  }
335  else if(nextValue == max)
336  {
337  if(m_isClamped && (value != previousValue))
338  {
339  color = blackColor;
340  }
341  else
342  {
343  color = previousColor;
344  }
345  }
346  else
347  {
348  // Interpolate the color.
349  const double distanceToNextValue = nextValue - value;
350  const double distanceToPreviousValue = value - previousValue;
351  const double distance = 1.0 / (nextValue - previousValue);
352  const double coefPrevious = 1.0 - (distanceToPreviousValue * distance);
353  const double coefNext = 1.0 - (distanceToNextValue * distance);
354 
355  color.r = coefPrevious*previousColor.r + coefNext*nextColor.r;
356  color.g = coefPrevious*previousColor.g + coefNext*nextColor.g;
357  color.b = coefPrevious*previousColor.b + coefNext*nextColor.b;
358  color.a = coefPrevious*previousColor.a + coefNext*nextColor.a;
359  }
360  return color;
361 }
362 
363 //------------------------------------------------------------------------------
364 
365 const TransferFunction::TFColor& TransferFunction::getTFColor( TFValueType value ) const
366 {
367  TFDataType::const_iterator itr = m_tfData.find(value);
368  OSLM_ASSERT("The value "<< value <<" is not defined in the transfer function.", itr != m_tfData.end());
369  return itr->second;
370 }
371 //------------------------------------------------------------------------------
372 
373 void TransferFunction::shallowCopy(const Object::csptr& _source )
374 {
375  TransferFunction::csptr other = TransferFunction::dynamicConstCast(_source);
376  FW_RAISE_EXCEPTION_IF( ::fwData::Exception(
377  "Unable to copy" + (_source ? _source->getClassname() : std::string("<NULL>"))
378  + " to " + this->getClassname()), !bool(other) );
379  this->fieldShallowCopy( _source );
380  this->m_level = other->m_level;
381  this->m_window = other->m_window;
382  this->m_name = other->m_name;
383  this->m_backgroundColor = other->m_backgroundColor;
384  this->m_tfData = other->m_tfData;
385  this->m_interpolationMode = other->m_interpolationMode;
386  this->m_isClamped = other->m_isClamped;
387 }
388 
389 //------------------------------------------------------------------------------
390 
391 void TransferFunction::cachedDeepCopy(const Object::csptr& _source, DeepCopyCacheType& cache)
392 {
393  TransferFunction::csptr other = TransferFunction::dynamicConstCast(_source);
394  FW_RAISE_EXCEPTION_IF( ::fwData::Exception(
395  "Unable to copy" + (_source ? _source->getClassname() : std::string("<NULL>"))
396  + " to " + this->getClassname()), !bool(other) );
397  this->fieldDeepCopy( _source, cache );
398  this->m_level = other->m_level;
399  this->m_window = other->m_window;
400  this->m_name = other->m_name;
401  this->m_backgroundColor = other->m_backgroundColor;
402  this->m_tfData = other->m_tfData;
403  this->m_interpolationMode = other->m_interpolationMode;
404  this->m_isClamped = other->m_isClamped;
405 }
406 
407 //------------------------------------------------------------------------------
408 
409 } // end namespace fwData
FWDATA_API void setWLMinMax(const TFValuePairType &minMax)
Set the min/max of the window level.
FWDATA_API void shallowCopy(const Object::csptr &_source) override
Shallow copy method.
FWDATA_API TFColor getNearestColor(TFValueType value) const
Get the nearest color of a value.
FWDATA_API TFValueVectorType getScaledValues() const
Get all the point values of the TF scaled and shifted with the window level.
static FWDATA_API const std::string s_DEFAULT_TF_NAME
Default transfer function name.
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
FWDATA_API void addTFColor(TFValueType value, const TFColor &color)
Add a new TF color point.
FWDATA_API const TFDataType & getTFData() const
Get all the TF data .
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
Implements data exception class.
FWDATA_API void clear()
Clear all the TF data.
FWDATA_API void cachedDeepCopy(const Object::csptr &_source, DeepCopyCacheType &cache) override
Deep copy method.
virtual const std::string & getClassname() const override
return full object&#39;s classname with its namespace, i.e. fwCore::BaseObject
FWDATA_API void fieldDeepCopy(const ::fwData::Object::csptr &source)
A deep copy of fields (objects in m_children)
FWDATA_API TFValuePairType getMinMaxTFValues() const
Get the first and last point values of the tf data.
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
FWDATA_API void eraseTFValue(TFValueType value)
Erase a TF color point.
FWDATA_API void setTFData(const TFDataType &tfData)
Set all the TF data (clear previous tf data).
FWDATA_API TFColorVectorType getTFColors() const
Get all the colors of the TF.
Contains the representation of the data objects used in the framework.
FWDATA_API void fieldShallowCopy(const ::fwData::Object::csptr &source)
A shallow copy of fields (objects in m_children)
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_WINDOWING_MODIFIED_SIG
Type of signal when points are modified.
FWDATA_API TFColor getLinearColor(TFValueType value) const
Get the color for a value (the color is computed with a linear interpolation).
FWDATA_API TFValueType getNearestValue(TFValueType value) const
Return the nearest point value of a value.
FWDATA_API TFValueVectorType getTFValues() const
Get all the point values of the TF (keys of the map m_tfData)
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_POINTS_MODIFIED_SIG
Type of signal when points are modified.
FWDATA_API TransferFunction(::fwData::Object::Key key)
Constructor.
FWDATA_API TFValuePairType getWLMinMax() const
Get the min/max of the window level.