|
@@ -0,0 +1,337 @@
|
|
|
+/*=========================================================================
|
|
|
+
|
|
|
+ Library: CTK
|
|
|
+
|
|
|
+ Copyright (c) 2010 Kitware Inc.
|
|
|
+
|
|
|
+ Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+ you may not use this file except in compliance with the License.
|
|
|
+ You may obtain a copy of the License at
|
|
|
+
|
|
|
+ http://www.commontk.org/LICENSE
|
|
|
+
|
|
|
+ Unless required by applicable law or agreed to in writing, software
|
|
|
+ distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+ See the License for the specific language governing permissions and
|
|
|
+ limitations under the License.
|
|
|
+
|
|
|
+=========================================================================*/
|
|
|
+
|
|
|
+/// Qt includes
|
|
|
+#include <QColor>
|
|
|
+#include <QDebug>
|
|
|
+
|
|
|
+/// CTK includes
|
|
|
+#include "ctkVTKHistogram.h"
|
|
|
+
|
|
|
+/// VTK includes
|
|
|
+#include <vtkDataArray.h>
|
|
|
+#include <vtkIntArray.h>
|
|
|
+#include <vtkMath.h>
|
|
|
+#include <vtkSmartPointer.h>
|
|
|
+
|
|
|
+/// STL include
|
|
|
+#include <limits>
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+class ctkVTKHistogramPrivate: public ctkPrivate<ctkVTKHistogram>
|
|
|
+{
|
|
|
+public:
|
|
|
+ ctkVTKHistogramPrivate();
|
|
|
+ vtkSmartPointer<vtkDataArray> DataArray;
|
|
|
+ vtkSmartPointer<vtkIntArray> Bins;
|
|
|
+ int UserNumberOfBins;
|
|
|
+ int Component;
|
|
|
+ mutable double Range[2];
|
|
|
+ int MinBin;
|
|
|
+ int MaxBin;
|
|
|
+
|
|
|
+ int computeNumberOfBins()const;
|
|
|
+};
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+ctkVTKHistogramPrivate::ctkVTKHistogramPrivate()
|
|
|
+{
|
|
|
+ this->Bins = vtkSmartPointer<vtkIntArray>::New();
|
|
|
+ this->UserNumberOfBins = -1;
|
|
|
+ this->Component = 0;
|
|
|
+ this->Range[0] = this->Range[1] = 0.;
|
|
|
+ this->MinBin = 0;
|
|
|
+ this->MaxBin = 0;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+int ctkVTKHistogramPrivate::computeNumberOfBins()const
|
|
|
+{
|
|
|
+ if (this->DataArray.GetPointer() == 0)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this->DataArray->GetDataType() == VTK_CHAR ||
|
|
|
+ this->DataArray->GetDataType() == VTK_SIGNED_CHAR ||
|
|
|
+ this->DataArray->GetDataType() == VTK_UNSIGNED_CHAR)
|
|
|
+ {
|
|
|
+ this->Range[0] = this->DataArray->GetDataTypeMin();
|
|
|
+ this->Range[1] = this->DataArray->GetDataTypeMax();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ this->DataArray->GetRange(this->Range, this->Component);
|
|
|
+ if (this->DataArray->GetDataType() == VTK_FLOAT ||
|
|
|
+ this->DataArray->GetDataType() == VTK_DOUBLE)
|
|
|
+ {
|
|
|
+ this->Range[1] += 0.01;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ this->Range[1] += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this->UserNumberOfBins > 0)
|
|
|
+ {
|
|
|
+ return this->UserNumberOfBins;
|
|
|
+ }
|
|
|
+
|
|
|
+ return static_cast<int>(this->Range[1] - this->Range[0]);
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+ctkVTKHistogram::ctkVTKHistogram(QObject* parentObject)
|
|
|
+ :ctkHistogram(parentObject)
|
|
|
+{
|
|
|
+ CTK_INIT_PRIVATE(ctkVTKHistogram);
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+ctkVTKHistogram::ctkVTKHistogram(vtkDataArray* dataArray,
|
|
|
+ QObject* parentObject)
|
|
|
+ :ctkHistogram(parentObject)
|
|
|
+{
|
|
|
+ CTK_INIT_PRIVATE(ctkVTKHistogram);
|
|
|
+ this->setDataArray(dataArray);
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+ctkVTKHistogram::~ctkVTKHistogram()
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+int ctkVTKHistogram::count()const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ return d->Bins->GetNumberOfTuples();
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkVTKHistogram::range(qreal& minRange, qreal& maxRange)const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ if (d->DataArray.GetPointer() == 0)
|
|
|
+ {
|
|
|
+ Q_ASSERT(d->DataArray.GetPointer());
|
|
|
+ minRange = 1.; // set incorrect values
|
|
|
+ maxRange = 0.;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (d->Range[0] == d->Range[1])
|
|
|
+ {
|
|
|
+ minRange = d->DataArray->GetDataTypeMin();
|
|
|
+ maxRange = d->DataArray->GetDataTypeMax();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ minRange = d->Range[0];
|
|
|
+ maxRange = d->Range[1];
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+QVariant ctkVTKHistogram::minValue()const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ return d->MinBin;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+QVariant ctkVTKHistogram::maxValue()const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ return d->MaxBin;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+ctkControlPoint* ctkVTKHistogram::controlPoint(int index)const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ ctkHistogramBar* cp = new ctkHistogramBar();
|
|
|
+ cp->P.X = this->indexToPos(index);
|
|
|
+ cp->P.Value = d->Bins->GetValue(index);
|
|
|
+ return cp;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+QVariant ctkVTKHistogram::value(qreal pos)const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ QSharedPointer<ctkControlPoint> point(this->controlPoint(this->posToIndex(pos)));
|
|
|
+ return point->value();
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+qreal ctkVTKHistogram::indexToPos(int index)const
|
|
|
+{
|
|
|
+ qreal posRange[2];
|
|
|
+ this->range(posRange[0], posRange[1]);
|
|
|
+ return posRange[0] + index * ((posRange[1] - posRange[0]) / (this->count() - 1));
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+int ctkVTKHistogram::posToIndex(qreal pos)const
|
|
|
+{
|
|
|
+ qreal posRange[2];
|
|
|
+ this->range(posRange[0], posRange[1]);
|
|
|
+ return (pos - posRange[0]) / ((posRange[1] - posRange[0]) / (this->count() - 1));
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkVTKHistogram::setDataArray(vtkDataArray* newDataArray)
|
|
|
+{
|
|
|
+ CTK_D(ctkVTKHistogram);
|
|
|
+ d->DataArray = newDataArray;
|
|
|
+ this->qvtkReconnect(d->DataArray,vtkCommand::ModifiedEvent,
|
|
|
+ this, SIGNAL(changed()));
|
|
|
+ emit changed();
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+vtkDataArray* ctkVTKHistogram::dataArray()const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ return d->DataArray;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkVTKHistogram::setComponent(int component)
|
|
|
+{
|
|
|
+ CTK_D(ctkVTKHistogram);
|
|
|
+ d->Component = component;
|
|
|
+ // need rebuild
|
|
|
+}
|
|
|
+
|
|
|
+int ctkVTKHistogram::component()const
|
|
|
+{
|
|
|
+ CTK_D(const ctkVTKHistogram);
|
|
|
+ return d->Component;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkVTKHistogram::setNumberOfBins(int number)
|
|
|
+{
|
|
|
+ CTK_D(ctkVTKHistogram);
|
|
|
+ d->UserNumberOfBins = number;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+template <class T>
|
|
|
+void populateBins(vtkIntArray* bins, const ctkVTKHistogram* histogram)
|
|
|
+{
|
|
|
+ vtkDataArray* scalars = histogram->dataArray();
|
|
|
+ int* binsPtr = bins->WritePointer(0, bins->GetNumberOfTuples());
|
|
|
+
|
|
|
+ // reset bins to 0
|
|
|
+ memset(binsPtr, bins->GetNumberOfTuples()*sizeof(int), 0);
|
|
|
+
|
|
|
+ const vtkIdType componentNumber = scalars->GetNumberOfComponents();
|
|
|
+ const vtkIdType tupleNumber = scalars->GetNumberOfTuples();
|
|
|
+ int component = histogram->component();
|
|
|
+
|
|
|
+ double range[2];
|
|
|
+ histogram->range(range[0], range[1]);
|
|
|
+ T offset = static_cast<T>(range[0]);
|
|
|
+
|
|
|
+ T* ptr = static_cast<T*>(scalars->WriteVoidPointer(0, tupleNumber));
|
|
|
+ T* endPtr = ptr + tupleNumber * componentNumber;
|
|
|
+ ptr += component;
|
|
|
+ for (; ptr < endPtr; ptr += componentNumber)
|
|
|
+ {
|
|
|
+ Q_ASSERT( (static_cast<long long>(*ptr) - offset) ==
|
|
|
+ (static_cast<int>(*ptr) - offset));
|
|
|
+ binsPtr[static_cast<int>(*ptr - offset)]++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+template <class T>
|
|
|
+void populateIrregularBins(vtkIntArray* bins, const ctkVTKHistogram* histogram)
|
|
|
+{
|
|
|
+ vtkDataArray* scalars = histogram->dataArray();
|
|
|
+
|
|
|
+ int* binsPtr = bins->WritePointer(0, bins->GetNumberOfTuples());
|
|
|
+ // reset bins to 0
|
|
|
+ memset(binsPtr, bins->GetNumberOfTuples() * sizeof(int), 0);
|
|
|
+
|
|
|
+ const vtkIdType componentNumber = scalars->GetNumberOfComponents();
|
|
|
+ const vtkIdType tupleNumber = scalars->GetNumberOfTuples();
|
|
|
+ int component = histogram->component();
|
|
|
+
|
|
|
+ double range[2];
|
|
|
+ histogram->range(range[0], range[1]);
|
|
|
+ double offset = range[0];
|
|
|
+
|
|
|
+ double binWidth = 1.;
|
|
|
+ if (range[1] != range[0])
|
|
|
+ {
|
|
|
+ binWidth = static_cast<double>(bins->GetNumberOfTuples()) / (range[1] - range[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ T* ptr = static_cast<T*>(scalars->WriteVoidPointer(0, tupleNumber));
|
|
|
+ T* endPtr = ptr + tupleNumber * componentNumber;
|
|
|
+ ptr += component;
|
|
|
+ for (; ptr < endPtr; ptr += componentNumber)
|
|
|
+ {
|
|
|
+ if (std::numeric_limits<T>::has_quiet_NaN &&
|
|
|
+ std::numeric_limits<T>::quiet_NaN() == *ptr)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ binsPtr[vtkMath::Floor(((double)*ptr - offset) * binWidth)]++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkVTKHistogram::build()
|
|
|
+{
|
|
|
+ CTK_D(ctkVTKHistogram);
|
|
|
+
|
|
|
+ const int binCount = d->computeNumberOfBins();
|
|
|
+
|
|
|
+ d->Bins->SetNumberOfComponents(1);
|
|
|
+ d->Bins->SetNumberOfTuples(binCount);
|
|
|
+
|
|
|
+ if (static_cast<double>(binCount) != (d->Range[1] - d->Range[2]))
|
|
|
+ {
|
|
|
+ switch(d->DataArray->GetDataType())
|
|
|
+ {
|
|
|
+ vtkTemplateMacro(populateIrregularBins<VTK_TT>(d->Bins, this));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ switch(d->DataArray->GetDataType())
|
|
|
+ {
|
|
|
+ vtkTemplateMacro(populateBins<VTK_TT>(d->Bins, this));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // update Min/Max values
|
|
|
+ int* binPtr = d->Bins->GetPointer(0);
|
|
|
+ int* endPtr = d->Bins->GetPointer(binCount-1);
|
|
|
+ d->MinBin = *endPtr;
|
|
|
+ d->MaxBin = *endPtr;
|
|
|
+ for (;binPtr < endPtr; ++binPtr)
|
|
|
+ {
|
|
|
+ d->MinBin = qMin(*binPtr, d->MinBin);
|
|
|
+ d->MaxBin = qMax(*binPtr, d->MaxBin);
|
|
|
+ }
|
|
|
+ emit changed();
|
|
|
+}
|