1 /*=========================================================================
2 
3   Library:   CTK
4 
5   Copyright (c) Kitware Inc.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11       http://www.apache.org/licenses/LICENSE-2.0.txt
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 =========================================================================*/
20 
21 /// Qt includes
22 #include <QColor>
23 #include <QDebug>
24 
25 /// CTK includes
26 #include "ctkVTKHistogram.h"
27 #include "ctkLogger.h"
28 
29 /// VTK includes
30 #include <vtkDataArray.h>
31 #include <vtkIntArray.h>
32 #include <vtkMath.h>
33 #include <vtkSmartPointer.h>
34 
35 /// STL include
36 #include <limits>
37 
38 //--------------------------------------------------------------------------
39 static ctkLogger logger("org.commontk.libs.visualization.core.ctkVTKHistogram");
40 //--------------------------------------------------------------------------
41 
42 //-----------------------------------------------------------------------------
43 class ctkVTKHistogramPrivate
44 {
45 public:
46   ctkVTKHistogramPrivate();
47   vtkSmartPointer<vtkDataArray> DataArray;
48   vtkSmartPointer<vtkIntArray>  Bins;
49   int                           UserNumberOfBins;
50   int                           Component;
51   mutable double                Range[2];
52   int                           MinBin;
53   int                           MaxBin;
54 
55   int computeNumberOfBins()const;
56 };
57 
58 //-----------------------------------------------------------------------------
ctkVTKHistogramPrivate()59 ctkVTKHistogramPrivate::ctkVTKHistogramPrivate()
60 {
61   this->Bins = vtkSmartPointer<vtkIntArray>::New();
62   this->UserNumberOfBins = -1;
63   this->Component = 0;
64   this->Range[0] = this->Range[1] = 0.;
65   this->MinBin = 0;
66   this->MaxBin = 0;
67 }
68 
69 //-----------------------------------------------------------------------------
computeNumberOfBins() const70 int ctkVTKHistogramPrivate::computeNumberOfBins()const
71 {
72   if (this->DataArray.GetPointer() == 0)
73     {
74     return -1;
75     }
76 
77   if (this->UserNumberOfBins > 0)
78     {
79     return this->UserNumberOfBins;
80     }
81 
82   return static_cast<int>(this->Range[1] - this->Range[0]) + 1;
83 }
84 
85 //-----------------------------------------------------------------------------
ctkVTKHistogram(QObject * parentObject)86 ctkVTKHistogram::ctkVTKHistogram(QObject* parentObject)
87   :ctkHistogram(parentObject)
88   , d_ptr(new ctkVTKHistogramPrivate)
89 {
90 }
91 
92 //-----------------------------------------------------------------------------
ctkVTKHistogram(vtkDataArray * dataArray,QObject * parentObject)93 ctkVTKHistogram::ctkVTKHistogram(vtkDataArray* dataArray,
94                                  QObject* parentObject)
95   :ctkHistogram(parentObject)
96   , d_ptr(new ctkVTKHistogramPrivate)
97 {
98   this->setDataArray(dataArray);
99 }
100 
101 //-----------------------------------------------------------------------------
~ctkVTKHistogram()102 ctkVTKHistogram::~ctkVTKHistogram()
103 {
104 }
105 
106 //-----------------------------------------------------------------------------
count() const107 int ctkVTKHistogram::count()const
108 {
109   Q_D(const ctkVTKHistogram);
110   return d->Bins->GetNumberOfTuples();
111 }
112 
113 //-----------------------------------------------------------------------------
setRange(qreal minRange,qreal maxRange)114 void ctkVTKHistogram::setRange(qreal minRange, qreal maxRange)
115 {
116   Q_D(const ctkVTKHistogram);
117   if (d->DataArray.GetPointer() == 0)
118     {
119     //Q_ASSERT(d->DataArray.GetPointer());
120     logger.warn("no data array. range will be reset when setting array.");
121     minRange = 1.; // set incorrect values
122     maxRange = 0.;
123     return;
124     }
125   if (minRange >= maxRange)
126     {
127     //Q_ASSERT(d->DataArray.GetPointer());
128     logger.warn("minRange >= maxRange");
129     qreal pivot = minRange;
130     minRange = maxRange;
131     maxRange = pivot;
132     }
133 
134   int numberOfBinsBefore = d->computeNumberOfBins();
135   d->Range[0] = minRange;
136   d->Range[1] = maxRange;
137   if (d->computeNumberOfBins() != numberOfBinsBefore)
138     {
139     this->build();
140     }
141 }
142 
143 //-----------------------------------------------------------------------------
range(qreal & minRange,qreal & maxRange) const144 void ctkVTKHistogram::range(qreal& minRange, qreal& maxRange)const
145 {
146   Q_D(const ctkVTKHistogram);
147   if (d->DataArray.GetPointer() == 0)
148     {
149     //Q_ASSERT(d->DataArray.GetPointer());
150     logger.warn("no dataArray");
151     minRange = 1.; // set incorrect values
152     maxRange = 0.;
153     return;
154     }
155   minRange = d->Range[0];
156   maxRange = d->Range[1];
157 }
158 
159 //-----------------------------------------------------------------------------
resetRange()160 void ctkVTKHistogram::resetRange()
161 {
162   Q_D(ctkVTKHistogram);
163   if (d->DataArray.GetPointer() == 0)
164     {
165     //Q_ASSERT(d->DataArray.GetPointer());
166     logger.warn("no dataArray");
167     d->Range[0] = 1.; // set incorrect values
168     d->Range[1] = 0.;
169     return;
170     }
171 
172   if (d->DataArray->GetDataType() == VTK_CHAR ||
173       d->DataArray->GetDataType() == VTK_SIGNED_CHAR ||
174       d->DataArray->GetDataType() == VTK_UNSIGNED_CHAR)
175     {
176     d->Range[0] = d->DataArray->GetDataTypeMin();
177     d->Range[1] = d->DataArray->GetDataTypeMax();
178     }
179   else
180     {
181     d->DataArray->GetRange(d->Range, d->Component);
182     if (d->DataArray->GetDataType() == VTK_FLOAT ||
183         d->DataArray->GetDataType() == VTK_DOUBLE)
184       {
185       d->Range[1] += 0.01;
186       }
187     //else
188     //  {
189     //  this->Range[1] += 1;
190     //  }
191     }
192 }
193 
194 //-----------------------------------------------------------------------------
minValue() const195 QVariant ctkVTKHistogram::minValue()const
196 {
197   //Q_D(const ctkVTKHistogram);
198   return 0;//d->MinBin;
199 }
200 
201 //-----------------------------------------------------------------------------
maxValue() const202 QVariant ctkVTKHistogram::maxValue()const
203 {
204   Q_D(const ctkVTKHistogram);
205   return d->MaxBin;
206 }
207 
208 //-----------------------------------------------------------------------------
controlPoint(int index) const209 ctkControlPoint* ctkVTKHistogram::controlPoint(int index)const
210 {
211   Q_D(const ctkVTKHistogram);
212   ctkHistogramBar* cp = new ctkHistogramBar();
213   cp->P.X = this->indexToPos(index);
214   cp->P.Value = d->Bins->GetValue(index);
215   return cp;
216 }
217 
218 //-----------------------------------------------------------------------------
value(qreal pos) const219 QVariant ctkVTKHistogram::value(qreal pos)const
220 {
221   QSharedPointer<ctkControlPoint> point(this->controlPoint(this->posToIndex(pos)));
222   return point->value();
223 }
224 
225 //-----------------------------------------------------------------------------
indexToPos(int index) const226 qreal ctkVTKHistogram::indexToPos(int index)const
227 {
228   qreal posRange[2];
229   this->range(posRange[0], posRange[1]);
230   return posRange[0] + index * ((posRange[1] - posRange[0]) / (this->count() - 1));
231 }
232 
233 //-----------------------------------------------------------------------------
posToIndex(qreal pos) const234 int ctkVTKHistogram::posToIndex(qreal pos)const
235 {
236   qreal posRange[2];
237   this->range(posRange[0], posRange[1]);
238   return (pos - posRange[0]) / ((posRange[1] - posRange[0]) / (this->count() - 1));
239 }
240 
241 //-----------------------------------------------------------------------------
setDataArray(vtkDataArray * newDataArray)242 void ctkVTKHistogram::setDataArray(vtkDataArray* newDataArray)
243 {
244   Q_D(ctkVTKHistogram);
245   if (newDataArray == d->DataArray)
246     {
247     return;
248     }
249 
250   d->DataArray = newDataArray;
251   this->resetRange();
252   this->qvtkReconnect(d->DataArray,vtkCommand::ModifiedEvent,
253                       this, SIGNAL(changed()));
254   emit changed();
255 }
256 
257 //-----------------------------------------------------------------------------
dataArray() const258 vtkDataArray* ctkVTKHistogram::dataArray()const
259 {
260   Q_D(const ctkVTKHistogram);
261   return d->DataArray;
262 }
263 
264 //-----------------------------------------------------------------------------
setComponent(int component)265 void ctkVTKHistogram::setComponent(int component)
266 {
267   Q_D(ctkVTKHistogram);
268   d->Component = component;
269   // need rebuild
270 }
271 
272 //-----------------------------------------------------------------------------
component() const273 int ctkVTKHistogram::component()const
274 {
275   Q_D(const ctkVTKHistogram);
276   return d->Component;
277 }
278 
279 //-----------------------------------------------------------------------------
numberOfBins() const280 int ctkVTKHistogram::numberOfBins()const
281 {
282   Q_D(const ctkVTKHistogram);
283   return d->UserNumberOfBins;
284 }
285 
286 //-----------------------------------------------------------------------------
setNumberOfBins(int number)287 void ctkVTKHistogram::setNumberOfBins(int number)
288 {
289   Q_D(ctkVTKHistogram);
290   d->UserNumberOfBins = number;
291 }
292 
293 //-----------------------------------------------------------------------------
294 template <class T>
populateBins(vtkIntArray * bins,const ctkVTKHistogram * histogram)295 void populateBins(vtkIntArray* bins, const ctkVTKHistogram* histogram)
296 {
297   vtkDataArray* scalars = histogram->dataArray();
298   int* binsPtr = bins->WritePointer(0, bins->GetNumberOfTuples());
299 
300   // reset bins to 0
301   memset(binsPtr, 0, bins->GetNumberOfComponents()*bins->GetNumberOfTuples()*sizeof(int));
302 
303   const vtkIdType componentNumber = scalars->GetNumberOfComponents();
304   const vtkIdType tupleNumber = scalars->GetNumberOfTuples();
305   int component = histogram->component();
306 
307   double range[2];
308   histogram->range(range[0], range[1]);
309   T offset = static_cast<T>(range[0]);
310 
311   T* ptr = static_cast<T*>(scalars->WriteVoidPointer(0, tupleNumber));
312   T* endPtr = ptr + tupleNumber * componentNumber;
313   ptr += component;
314   vtkIdType histogramSize = bins->GetNumberOfTuples();
315   for (; ptr < endPtr; ptr += componentNumber)
316     {
317     int index = static_cast<int>(*ptr - offset);
318     if (index < 0 || index >= histogramSize)
319       {
320       // This happens when scalar range is not computed correctly
321       // (scalar range may be read from file, so VTK does not have full control over it)
322       continue;
323       }
324     binsPtr[index]++;
325     }
326 }
327 
328 //-----------------------------------------------------------------------------
329 template <class T>
populateIrregularBins(vtkIntArray * bins,const ctkVTKHistogram * histogram)330 void populateIrregularBins(vtkIntArray* bins, const ctkVTKHistogram* histogram)
331 {
332   vtkDataArray* scalars = histogram->dataArray();
333 
334   int* binsPtr = bins->WritePointer(0, bins->GetNumberOfComponents()*bins->GetNumberOfTuples());
335   // reset bins to 0
336   memset(binsPtr, 0, bins->GetNumberOfTuples() * sizeof(int));
337 
338   const vtkIdType componentNumber = scalars->GetNumberOfComponents();
339   const vtkIdType tupleNumber = scalars->GetNumberOfTuples();
340   int component = histogram->component();
341 
342   double range[2];
343   histogram->range(range[0], range[1]);
344   double offset = range[0];
345 
346   double binWidth = 1.;
347   if (range[1] != range[0])
348     {
349     binWidth = static_cast<double>(bins->GetNumberOfTuples()-1) / (range[1] - range[0]);
350     }
351 
352   T* ptr = static_cast<T*>(scalars->WriteVoidPointer(0, tupleNumber));
353   T* endPtr = ptr + tupleNumber * componentNumber;
354   ptr += component;
355   vtkIdType histogramSize = bins->GetNumberOfTuples();
356   for (; ptr < endPtr; ptr += componentNumber)
357     {
358     if ((std::numeric_limits<T>::has_quiet_NaN &&
359       vtkMath::IsNan(*ptr)) || vtkMath::IsInf(*ptr))
360       {
361       continue;
362       }
363     int index = vtkMath::Floor((static_cast<double>(*ptr) - offset) * binWidth);
364     if (index < 0 || index >= histogramSize)
365       {
366       // This happens when scalar range is not computed correctly
367       // (scalar range may be read from file, so VTK does not have full control over it)
368       continue;
369       }
370     binsPtr[index]++;
371     }
372 }
373 
374 //-----------------------------------------------------------------------------
build()375 void ctkVTKHistogram::build()
376 {
377   Q_D(ctkVTKHistogram);
378 
379   if (d->DataArray.GetPointer() == 0)
380     {
381     d->MinBin = 0;
382     d->MaxBin = 0;
383     d->Bins->SetNumberOfTuples(0);
384     return;
385     }
386 
387   const int binCount = d->computeNumberOfBins();
388 
389   d->Bins->SetNumberOfComponents(1);
390   d->Bins->SetNumberOfTuples(binCount);
391 
392   if (binCount <= 0)
393     {
394     d->MinBin = 0;
395     d->MaxBin = 0;
396     return;
397     }
398 
399   // What is the type of the array, discrete or reals
400   if (static_cast<double>(binCount) != (d->Range[1] - d->Range[0] + 1))
401     {
402     switch(d->DataArray->GetDataType())
403       {
404       vtkTemplateMacro(populateIrregularBins<VTK_TT>(d->Bins, this));
405       }
406     }
407   else
408     {
409     switch(d->DataArray->GetDataType())
410       {
411       vtkTemplateMacro(populateBins<VTK_TT>(d->Bins, this));
412       }
413     }
414   // update Min/Max values
415   int* binPtr = d->Bins->GetPointer(0);
416   int* endPtr = d->Bins->GetPointer(binCount-1);
417   d->MinBin = *endPtr;
418   d->MaxBin = *endPtr;
419   for (;binPtr < endPtr; ++binPtr)
420     {
421     d->MinBin = qMin(*binPtr, d->MinBin);
422     d->MaxBin = qMax(*binPtr, d->MaxBin);
423     }
424   emit changed();
425 }
426 
427 //-----------------------------------------------------------------------------
removeControlPoint(qreal pos)428 void ctkVTKHistogram::removeControlPoint( qreal pos )
429 {
430   Q_UNUSED(pos);
431   // TO BE IMPLEMENTED
432 }
433