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