mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
1044 lines
27 KiB
C++
1044 lines
27 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkPlotPoints.cxx
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
|
|
#include "vtkPlotPoints.h"
|
|
|
|
#include "vtkNew.h"
|
|
#include "vtkContext2D.h"
|
|
#include "vtkPen.h"
|
|
#include "vtkBrush.h"
|
|
#include "vtkAxis.h"
|
|
#include "vtkContextMapper2D.h"
|
|
#include "vtkPoints2D.h"
|
|
#include "vtkTable.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkIdTypeArray.h"
|
|
#include "vtkImageData.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkCharArray.h"
|
|
#include "vtkUnsignedCharArray.h"
|
|
#include "vtkLookupTable.h"
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include <set>
|
|
|
|
// PIMPL for STL vector...
|
|
struct vtkIndexedVector2f
|
|
{
|
|
size_t index;
|
|
vtkVector2f pos;
|
|
};
|
|
|
|
class vtkPlotPoints::VectorPIMPL : public std::vector<vtkIndexedVector2f>
|
|
{
|
|
public:
|
|
VectorPIMPL(vtkVector2f* array, size_t n)
|
|
: std::vector<vtkIndexedVector2f>()
|
|
{
|
|
this->reserve(n);
|
|
for (size_t i = 0; i < n; ++i)
|
|
{
|
|
vtkIndexedVector2f tmp;
|
|
tmp.index = i;
|
|
tmp.pos = array[i];
|
|
this->push_back(tmp);
|
|
}
|
|
}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkStandardNewMacro(vtkPlotPoints)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkPlotPoints::vtkPlotPoints()
|
|
{
|
|
this->Points = NULL;
|
|
this->Sorted = NULL;
|
|
this->BadPoints = NULL;
|
|
this->ValidPointMask = NULL;
|
|
this->MarkerStyle = vtkPlotPoints::CIRCLE;
|
|
this->MarkerSize = -1.0;
|
|
this->LogX = false;
|
|
this->LogY = false;
|
|
|
|
this->LookupTable = 0;
|
|
this->Colors = 0;
|
|
this->ScalarVisibility = 0;
|
|
|
|
this->UnscaledInputBounds[0] = this->UnscaledInputBounds[2] = vtkMath::Inf();
|
|
this->UnscaledInputBounds[1] = this->UnscaledInputBounds[3] = -vtkMath::Inf();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkPlotPoints::~vtkPlotPoints()
|
|
{
|
|
if (this->Points)
|
|
{
|
|
this->Points->Delete();
|
|
this->Points = NULL;
|
|
}
|
|
delete this->Sorted;
|
|
if (this->BadPoints)
|
|
{
|
|
this->BadPoints->Delete();
|
|
this->BadPoints = NULL;
|
|
}
|
|
if (this->LookupTable)
|
|
{
|
|
this->LookupTable->UnRegister(this);
|
|
}
|
|
if ( this->Colors != 0 )
|
|
{
|
|
this->Colors->UnRegister(this);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::Update()
|
|
{
|
|
if (!this->Visible)
|
|
{
|
|
return;
|
|
}
|
|
// Check if we have an input
|
|
vtkTable *table = this->Data->GetInput();
|
|
|
|
if (table && !this->ValidPointMaskName.empty() &&
|
|
table->GetColumnByName(this->ValidPointMaskName))
|
|
{
|
|
this->ValidPointMask = vtkCharArray::SafeDownCast(
|
|
table->GetColumnByName(this->ValidPointMaskName));
|
|
}
|
|
else
|
|
{
|
|
this->ValidPointMask = 0;
|
|
}
|
|
|
|
if (!table)
|
|
{
|
|
vtkDebugMacro(<< "Update event called with no input table set.");
|
|
return;
|
|
}
|
|
else if(this->Data->GetMTime() > this->BuildTime ||
|
|
table->GetMTime() > this->BuildTime ||
|
|
(this->LookupTable && this->LookupTable->GetMTime() > this->BuildTime) ||
|
|
this->MTime > this->BuildTime)
|
|
{
|
|
vtkDebugMacro(<< "Updating cached values.");
|
|
this->UpdateTableCache(table);
|
|
}
|
|
else if (this->XAxis && this->YAxis &&
|
|
((this->XAxis->GetMTime() > this->BuildTime) ||
|
|
(this->YAxis->GetMTime() > this->BuildTime)))
|
|
{
|
|
if ((this->LogX != this->XAxis->GetLogScale()) ||
|
|
(this->LogY != this->YAxis->GetLogScale()))
|
|
{
|
|
this->UpdateTableCache(table);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotPoints::Paint(vtkContext2D *painter)
|
|
{
|
|
// This is where everything should be drawn, or dispatched to other methods.
|
|
vtkDebugMacro(<< "Paint event called in vtkPlotPoints.");
|
|
|
|
if (!this->Visible || !this->Points || this->Points->GetNumberOfPoints() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Maintain legacy behavior (using pen width) if MarkerSize was not set
|
|
float width = this->MarkerSize;
|
|
if (width < 0.0f)
|
|
{
|
|
width = this->Pen->GetWidth() * 2.3;
|
|
if (width < 8.0)
|
|
{
|
|
width = 8.0;
|
|
}
|
|
}
|
|
|
|
// If there is a marker style, then draw the marker for each point too
|
|
if (this->MarkerStyle != VTK_MARKER_NONE)
|
|
{
|
|
painter->ApplyPen(this->Pen);
|
|
painter->ApplyBrush(this->Brush);
|
|
painter->GetPen()->SetWidth(width);
|
|
|
|
float *points = static_cast<float *>(this->Points->GetVoidPointer(0));
|
|
unsigned char *colors = 0;
|
|
int nColorComponents = 0;
|
|
if (this->ScalarVisibility && this->Colors)
|
|
{
|
|
colors = this->Colors->GetPointer(0);
|
|
nColorComponents = static_cast<int>(this->Colors->GetNumberOfComponents());
|
|
}
|
|
|
|
if (this->BadPoints && this->BadPoints->GetNumberOfTuples() > 0)
|
|
{
|
|
vtkIdType lastGood = 0;
|
|
|
|
for (vtkIdType i = 0; i < this->BadPoints->GetNumberOfTuples(); i++)
|
|
{
|
|
vtkIdType id = this->BadPoints->GetValue(i);
|
|
|
|
// render from last good point to one before this bad point
|
|
if (id - lastGood > 2)
|
|
{
|
|
painter->DrawMarkers(this->MarkerStyle, false,
|
|
points + 2 * (lastGood + 1),
|
|
id - lastGood - 1,
|
|
colors ? colors + 4 * (lastGood + 1) : 0,
|
|
nColorComponents);
|
|
}
|
|
|
|
lastGood = id;
|
|
}
|
|
|
|
// render any trailing good points
|
|
if (this->Points->GetNumberOfPoints() - lastGood > 2)
|
|
{
|
|
painter->DrawMarkers(this->MarkerStyle, false,
|
|
points + 2 * (lastGood + 1),
|
|
this->Points->GetNumberOfPoints() - lastGood - 1,
|
|
colors ? colors + 4 * (lastGood + 1) : 0,
|
|
nColorComponents);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// draw all of the points
|
|
painter->DrawMarkers(this->MarkerStyle, false,
|
|
points, this->Points->GetNumberOfPoints(),
|
|
colors, nColorComponents);
|
|
}
|
|
}
|
|
|
|
// Now add some decorations for our selected points...
|
|
if (this->Selection && this->Selection->GetNumberOfTuples())
|
|
{
|
|
if (this->Selection->GetMTime() > this->SelectedPoints->GetMTime() ||
|
|
this->GetMTime() > this->SelectedPoints->GetMTime())
|
|
{
|
|
float *f = vtkFloatArray::SafeDownCast(
|
|
this->Points->GetData())->GetPointer(0);
|
|
int nSelected(static_cast<int>(this->Selection->GetNumberOfTuples()));
|
|
this->SelectedPoints->SetNumberOfComponents(2);
|
|
this->SelectedPoints->SetNumberOfTuples(nSelected);
|
|
float *selectedPtr = static_cast<float *>(this->SelectedPoints->GetVoidPointer(0));
|
|
for (int i = 0; i < nSelected; ++i)
|
|
{
|
|
*(selectedPtr++) = f[2 * this->Selection->GetValue(i)];
|
|
*(selectedPtr++) = f[2 * this->Selection->GetValue(i) + 1];
|
|
}
|
|
}
|
|
vtkDebugMacro(<<"Selection set " << this->Selection->GetNumberOfTuples());
|
|
painter->GetPen()->SetColor(this->SelectionPen->GetColor());
|
|
painter->GetPen()->SetOpacity(this->SelectionPen->GetOpacity());
|
|
painter->GetPen()->SetWidth(width + 2.7);
|
|
|
|
if (this->MarkerStyle == VTK_MARKER_NONE)
|
|
{
|
|
painter->DrawMarkers(VTK_MARKER_PLUS, false,
|
|
static_cast<float *>(
|
|
this->SelectedPoints->GetVoidPointer(0)),
|
|
this->SelectedPoints->GetNumberOfTuples());
|
|
}
|
|
else
|
|
{
|
|
painter->DrawMarkers(this->MarkerStyle, true,
|
|
static_cast<float *>(
|
|
this->SelectedPoints->GetVoidPointer(0)),
|
|
this->SelectedPoints->GetNumberOfTuples());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotPoints::PaintLegend(vtkContext2D *painter, const vtkRectf& rect,
|
|
int)
|
|
{
|
|
if (this->MarkerStyle)
|
|
{
|
|
float width = this->Pen->GetWidth() * 2.3;
|
|
if (width < 8.0)
|
|
{
|
|
width = 8.0;
|
|
}
|
|
painter->ApplyPen(this->Pen);
|
|
painter->ApplyBrush(this->Brush);
|
|
painter->GetPen()->SetWidth(width);
|
|
|
|
float point[] = { rect[0]+ 0.5f * rect[2], rect[1] + 0.5f * rect[3] };
|
|
painter->DrawMarkers(this->MarkerStyle, false, point, 1);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::GetBounds(double bounds[4])
|
|
{
|
|
if (this->Points)
|
|
{
|
|
// There are bad points in the series - need to do this ourselves.
|
|
this->CalculateBounds(bounds);
|
|
}
|
|
vtkDebugMacro(<< "Bounds: " << bounds[0] << "\t" << bounds[1] << "\t"
|
|
<< bounds[2] << "\t" << bounds[3]);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::GetUnscaledInputBounds(double bounds[4])
|
|
{
|
|
this->CalculateUnscaledInputBounds();
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
bounds[i] = this->UnscaledInputBounds[i];
|
|
}
|
|
vtkDebugMacro(
|
|
<< "Bounds: " << bounds[0] << "\t" << bounds[1] << "\t"
|
|
<< bounds[2] << "\t" << bounds[3]);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
bool compVector3fX(const vtkIndexedVector2f& v1,
|
|
const vtkIndexedVector2f& v2)
|
|
{
|
|
if (v1.pos.GetX() < v2.pos.GetX())
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// See if the point is within tolerance.
|
|
bool inRange(const vtkVector2f& point, const vtkVector2f& tol,
|
|
const vtkVector2f& current)
|
|
{
|
|
if (current.GetX() > point.GetX() - tol.GetX() && current.GetX() < point.GetX() + tol.GetX() &&
|
|
current.GetY() > point.GetY() - tol.GetY() && current.GetY() < point.GetY() + tol.GetY())
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::CreateSortedPoints()
|
|
{
|
|
// Sort the data if it has not been done already...
|
|
if (!this->Sorted)
|
|
{
|
|
vtkIdType n = this->Points->GetNumberOfPoints();
|
|
vtkVector2f* data =
|
|
static_cast<vtkVector2f*>(this->Points->GetVoidPointer(0));
|
|
this->Sorted = new VectorPIMPL(data, n);
|
|
std::sort(this->Sorted->begin(), this->Sorted->end(), compVector3fX);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkIdType vtkPlotPoints::GetNearestPoint(const vtkVector2f& point,
|
|
const vtkVector2f& tol,
|
|
vtkVector2f* location)
|
|
{
|
|
// Right now doing a simple bisector search of the array.
|
|
if (!this->Points)
|
|
{
|
|
return -1;
|
|
}
|
|
this->CreateSortedPoints();
|
|
|
|
// Set up our search array, use the STL lower_bound algorithm
|
|
VectorPIMPL::iterator low;
|
|
VectorPIMPL &v = *this->Sorted;
|
|
|
|
// Get the lowest point we might hit within the supplied tolerance
|
|
vtkIndexedVector2f lowPoint;
|
|
lowPoint.index = 0;
|
|
lowPoint.pos = vtkVector2f(point.GetX()-tol.GetX(), 0.0f);
|
|
low = std::lower_bound(v.begin(), v.end(), lowPoint, compVector3fX);
|
|
|
|
// Now consider the y axis
|
|
float highX = point.GetX() + tol.GetX();
|
|
while (low != v.end())
|
|
{
|
|
if (inRange(point, tol, (*low).pos))
|
|
{
|
|
*location = (*low).pos;
|
|
return static_cast<int>((*low).index);
|
|
}
|
|
else if (low->pos.GetX() > highX)
|
|
{
|
|
break;
|
|
}
|
|
++low;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotPoints::SelectPoints(const vtkVector2f& min, const vtkVector2f& max)
|
|
{
|
|
if (!this->Points)
|
|
{
|
|
return false;
|
|
}
|
|
this->CreateSortedPoints();
|
|
|
|
if (!this->Selection)
|
|
{
|
|
this->Selection = vtkIdTypeArray::New();
|
|
}
|
|
this->Selection->SetNumberOfTuples(0);
|
|
|
|
// Set up our search array, use the STL lower_bound algorithm
|
|
VectorPIMPL::iterator low;
|
|
VectorPIMPL &v = *this->Sorted;
|
|
|
|
// Get the lowest point we might hit within the supplied tolerance
|
|
vtkIndexedVector2f lowPoint;
|
|
lowPoint.index = 0;
|
|
lowPoint.pos = min;
|
|
low = std::lower_bound(v.begin(), v.end(), lowPoint, compVector3fX);
|
|
|
|
// Output a sorted selection list too.
|
|
std::vector<vtkIdType> selected;
|
|
// Iterate until we are out of range in X
|
|
while (low != v.end())
|
|
{
|
|
if (low->pos.GetX() >= min.GetX() && low->pos.GetX() <= max.GetX() &&
|
|
low->pos.GetY() >= min.GetY() && low->pos.GetY() <= max.GetY())
|
|
{
|
|
selected.push_back(low->index);
|
|
}
|
|
else if (low->pos.GetX() > max.GetX())
|
|
{
|
|
break;
|
|
}
|
|
++low;
|
|
}
|
|
this->Selection->SetNumberOfTuples(selected.size());
|
|
vtkIdType *ptr = static_cast<vtkIdType *>(this->Selection->GetVoidPointer(0));
|
|
for (size_t i = 0; i < selected.size(); ++i)
|
|
{
|
|
ptr[i] = selected[i];
|
|
}
|
|
std::sort(ptr, ptr + selected.size());
|
|
this->Selection->Modified();
|
|
return this->Selection->GetNumberOfTuples() > 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotPoints::SelectPointsInPolygon(const vtkContextPolygon &polygon)
|
|
{
|
|
if (!this->Points)
|
|
{
|
|
// nothing to select
|
|
return false;
|
|
}
|
|
|
|
if (!this->Selection)
|
|
{
|
|
// create selection object
|
|
this->Selection = vtkIdTypeArray::New();
|
|
}
|
|
else
|
|
{
|
|
// clear previous selection
|
|
this->Selection->SetNumberOfValues(0);
|
|
}
|
|
|
|
for(vtkIdType pointId = 0;
|
|
pointId < this->Points->GetNumberOfPoints();
|
|
pointId++)
|
|
{
|
|
// get point location
|
|
double point[3];
|
|
this->Points->GetPoint(pointId, point);
|
|
|
|
if (polygon.Contains(vtkVector2f(point[0], point[1])))
|
|
{
|
|
this->Selection->InsertNextValue(pointId);
|
|
}
|
|
}
|
|
|
|
// return true if we selected any points
|
|
return this->Selection->GetNumberOfTuples() > 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace {
|
|
|
|
// Find any bad points in the supplied array.
|
|
template<typename T>
|
|
void SetBadPoints(T *data, vtkIdType n, std::set<vtkIdType> &bad)
|
|
{
|
|
for (vtkIdType i = 0; i < n; ++i)
|
|
{
|
|
if (vtkMath::IsInf(data[i]) || vtkMath::IsNan(data[i]))
|
|
{
|
|
bad.insert(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate the bounds from the original data.
|
|
template<typename A>
|
|
void ComputeBounds(A *a, int n, double bounds[2])
|
|
{
|
|
bounds[0] = std::numeric_limits<double>::max();
|
|
bounds[1] = -std::numeric_limits<double>::max();
|
|
for (int i = 0; i < n; ++a, ++i)
|
|
{
|
|
bounds[0] = bounds[0] < *a ? bounds[0] : *a;
|
|
bounds[1] = bounds[1] > *a ? bounds[1] : *a;
|
|
}
|
|
}
|
|
|
|
template<typename A>
|
|
void ComputeBounds(A *a, int n, vtkIdTypeArray *bad, double bounds[2])
|
|
{
|
|
// If possible, use the simpler code without any bad points.
|
|
if (!bad || bad->GetNumberOfTuples() == 0)
|
|
{
|
|
ComputeBounds(a, n, bounds);
|
|
return;
|
|
}
|
|
|
|
// Initialize the first range of points.
|
|
vtkIdType start = 0;
|
|
vtkIdType end = 0;
|
|
vtkIdType i = 0;
|
|
vtkIdType nBad = bad->GetNumberOfTuples();
|
|
if (bad->GetValue(i) == 0)
|
|
{
|
|
while (i < nBad && i == bad->GetValue(i))
|
|
{
|
|
start = bad->GetValue(i++) + 1;
|
|
}
|
|
if (start < n)
|
|
{
|
|
end = n;
|
|
}
|
|
else
|
|
{
|
|
// They are all bad points, return early.
|
|
return;
|
|
}
|
|
}
|
|
if (i < nBad)
|
|
{
|
|
end = bad->GetValue(i++);
|
|
}
|
|
else
|
|
{
|
|
end = n;
|
|
}
|
|
|
|
bounds[0] = std::numeric_limits<double>::max();
|
|
bounds[1] = -std::numeric_limits<double>::max();
|
|
while (start < n)
|
|
{
|
|
// Calculate the min/max in this range.
|
|
while (start < end)
|
|
{
|
|
bounds[0] = bounds[0] < a[start] ? bounds[0] : a[start];
|
|
bounds[1] = bounds[1] > a[start] ? bounds[1] : a[start];
|
|
++start;
|
|
}
|
|
// Now figure out the next range to be evaluated.
|
|
start = end + 1;
|
|
while (i < nBad && start == bad->GetValue(i))
|
|
{
|
|
start = bad->GetValue(i++) + 1;
|
|
}
|
|
if (i < nBad)
|
|
{
|
|
end = bad->GetValue(i++);
|
|
}
|
|
else
|
|
{
|
|
end = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dispatch this call off to the right function.
|
|
template<typename A>
|
|
void ComputeBounds(A *a, vtkDataArray *b, int n, vtkIdTypeArray *bad,
|
|
double bounds[4])
|
|
{
|
|
ComputeBounds(a, n, bad, bounds);
|
|
switch(b->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
ComputeBounds(static_cast<VTK_TT*>(b->GetVoidPointer(0)), n, bad,
|
|
&bounds[2]));
|
|
}
|
|
}
|
|
|
|
// Copy the two arrays into the points array
|
|
template<typename A, typename B>
|
|
void CopyToPoints(vtkPoints2D *points, A *a, B *b, int n, const vtkRectd &ss)
|
|
{
|
|
points->SetNumberOfPoints(n);
|
|
float* data = static_cast<float*>(points->GetVoidPointer(0));
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
data[2 * i] = static_cast<float>((a[i] + ss[0]) * ss[2]);
|
|
data[2 * i + 1] = static_cast<float>((b[i] + ss[1]) * ss[3]);
|
|
}
|
|
}
|
|
|
|
// Copy one array into the points array, use the index of that array as x
|
|
template<typename A>
|
|
void CopyToPoints(vtkPoints2D *points, A *a, int n, const vtkRectd &ss)
|
|
{
|
|
points->SetNumberOfPoints(n);
|
|
float* data = static_cast<float*>(points->GetVoidPointer(0));
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
data[2 * i] = static_cast<float>(( i + ss[0]) * ss[2]);
|
|
data[2 * i + 1] = static_cast<float>((a[i] + ss[1]) * ss[3]);
|
|
}
|
|
}
|
|
|
|
// Copy the two arrays into the points array
|
|
template<typename A>
|
|
void CopyToPointsSwitch(vtkPoints2D *points, A *a, vtkDataArray *b, int n,
|
|
const vtkRectd &ss)
|
|
{
|
|
switch(b->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
CopyToPoints(
|
|
points, a, static_cast<VTK_TT*>(b->GetVoidPointer(0)), n, ss));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotPoints::GetDataArrays(vtkTable *table, vtkDataArray *array[2])
|
|
{
|
|
if (!table)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get the x and y arrays (index 0 and 1 respectively)
|
|
array[0] = this->UseIndexForXSeries ?
|
|
0 : this->Data->GetInputArrayToProcess(0, table);
|
|
array[1] = this->Data->GetInputArrayToProcess(1, table);
|
|
|
|
if (!array[0] && !this->UseIndexForXSeries)
|
|
{
|
|
vtkErrorMacro(<< "No X column is set (index 0).");
|
|
return false;
|
|
}
|
|
else if (!array[1])
|
|
{
|
|
vtkErrorMacro(<< "No Y column is set (index 1).");
|
|
return false;
|
|
}
|
|
else if (!this->UseIndexForXSeries &&
|
|
array[0]->GetNumberOfTuples() != array[1]->GetNumberOfTuples())
|
|
{
|
|
vtkErrorMacro("The x and y columns must have the same number of elements. "
|
|
<< array[0]->GetNumberOfTuples() << ", "
|
|
<< array[1]->GetNumberOfTuples());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotPoints::UpdateTableCache(vtkTable *table)
|
|
{
|
|
vtkDataArray *array[2] = { 0, 0 };
|
|
if (!this->GetDataArrays(table, array))
|
|
{
|
|
this->BuildTime.Modified();
|
|
return false;
|
|
}
|
|
|
|
if (!this->Points)
|
|
{
|
|
this->Points = vtkPoints2D::New();
|
|
}
|
|
vtkDataArray *x = array[0];
|
|
vtkDataArray *y = array[1];
|
|
|
|
// Now copy the components into their new columns
|
|
if (this->UseIndexForXSeries)
|
|
{
|
|
switch(y->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
CopyToPoints(
|
|
this->Points, static_cast<VTK_TT*>(y->GetVoidPointer(0)),
|
|
y->GetNumberOfTuples(), this->ShiftScale));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(x->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
CopyToPointsSwitch(
|
|
this->Points, static_cast<VTK_TT*>(x->GetVoidPointer(0)),
|
|
y, x->GetNumberOfTuples(), this->ShiftScale));
|
|
}
|
|
}
|
|
this->CalculateLogSeries();
|
|
this->FindBadPoints();
|
|
this->Points->Modified();
|
|
delete this->Sorted;
|
|
this->Sorted = 0;
|
|
|
|
// Additions for color mapping
|
|
if (this->ScalarVisibility && !this->ColorArrayName.empty())
|
|
{
|
|
vtkDataArray* c =
|
|
vtkDataArray::SafeDownCast(table->GetColumnByName(this->ColorArrayName));
|
|
// TODO: Should add support for categorical coloring & try enum lookup
|
|
if (c)
|
|
{
|
|
if (!this->LookupTable)
|
|
{
|
|
this->CreateDefaultLookupTable();
|
|
}
|
|
if (this->Colors)
|
|
{
|
|
this->Colors->UnRegister(this);
|
|
}
|
|
this->Colors = this->LookupTable->MapScalars(c, VTK_COLOR_MODE_MAP_SCALARS, -1);
|
|
// Consistent register and unregisters
|
|
this->Colors->Register(this);
|
|
this->Colors->Delete();
|
|
}
|
|
else
|
|
{
|
|
this->Colors->UnRegister(this);
|
|
this->Colors = 0;
|
|
}
|
|
}
|
|
|
|
this->BuildTime.Modified();
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::CalculateUnscaledInputBounds()
|
|
{
|
|
vtkTable *table = this->Data->GetInput();
|
|
vtkDataArray *array[2] = { 0, 0 };
|
|
if (!this->GetDataArrays(table, array))
|
|
{
|
|
return;
|
|
}
|
|
// Now copy the components into their new columns
|
|
if (this->UseIndexForXSeries)
|
|
{
|
|
this->UnscaledInputBounds[0] = 0.0;
|
|
this->UnscaledInputBounds[1] = array[1]->GetNumberOfTuples() - 1;
|
|
switch(array[1]->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
ComputeBounds(static_cast<VTK_TT*>(array[1]->GetVoidPointer(0)),
|
|
array[1]->GetNumberOfTuples(), this->BadPoints,
|
|
&this->UnscaledInputBounds[2]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(array[0]->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
ComputeBounds(static_cast<VTK_TT*>(array[0]->GetVoidPointer(0)),
|
|
array[1], array[0]->GetNumberOfTuples(), this->BadPoints,
|
|
this->UnscaledInputBounds));
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::CalculateLogSeries()
|
|
{
|
|
if (!this->XAxis || !this->YAxis)
|
|
{
|
|
return;
|
|
}
|
|
this->LogX = this->XAxis->GetLogScaleActive();
|
|
this->LogY = this->YAxis->GetLogScaleActive();
|
|
float* data = static_cast<float*>(this->Points->GetVoidPointer(0));
|
|
vtkIdType n = this->Points->GetNumberOfPoints();
|
|
if (this->LogX)
|
|
{
|
|
if (this->XAxis->GetUnscaledMinimum() < 0.)
|
|
{
|
|
for (vtkIdType i = 0; i < n; ++i)
|
|
{
|
|
data[2*i] = log10(fabs(data[2*i]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (vtkIdType i = 0; i < n; ++i)
|
|
{
|
|
data[2*i] = log10(data[2*i]);
|
|
}
|
|
}
|
|
}
|
|
if (this->LogY)
|
|
{
|
|
if (this->YAxis->GetUnscaledMinimum() < 0.)
|
|
{
|
|
for (vtkIdType i = 0; i < n; ++i)
|
|
{
|
|
data[2*i+1] = log10(fabs(data[2*i+1]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (vtkIdType i = 0; i < n; ++i)
|
|
{
|
|
data[2*i+1] = log10(data[2*i+1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::FindBadPoints()
|
|
{
|
|
// This should be run after CalculateLogSeries as a final step.
|
|
vtkIdType n = this->Points->GetNumberOfPoints();
|
|
|
|
// Scan through and find any bad points.
|
|
vtkTable *table = this->Data->GetInput();
|
|
vtkDataArray *array[2] = { 0, 0 };
|
|
if (!this->GetDataArrays(table, array))
|
|
{
|
|
return;
|
|
}
|
|
std::set<vtkIdType> bad;
|
|
if (!this->UseIndexForXSeries)
|
|
{
|
|
switch(array[0]->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
SetBadPoints(static_cast<VTK_TT*>(array[0]->GetVoidPointer(0)), n, bad));
|
|
}
|
|
}
|
|
switch(array[1]->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
SetBadPoints(static_cast<VTK_TT*>(array[1]->GetVoidPointer(0)), n, bad));
|
|
}
|
|
|
|
// add points from the ValidPointMask
|
|
if (this->ValidPointMask)
|
|
{
|
|
for (vtkIdType i = 0; i < n; i++)
|
|
{
|
|
if (this->ValidPointMask->GetValue(i) == 0)
|
|
{
|
|
bad.insert(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there are bad points copy them, if not ensure the pointer is null.
|
|
if (!bad.empty())
|
|
{
|
|
if (!this->BadPoints)
|
|
{
|
|
this->BadPoints = vtkIdTypeArray::New();
|
|
}
|
|
else
|
|
{
|
|
this->BadPoints->SetNumberOfTuples(0);
|
|
}
|
|
for (std::set<vtkIdType>::const_iterator it = bad.begin();
|
|
it != bad.end(); ++it)
|
|
{
|
|
this->BadPoints->InsertNextValue(*it);
|
|
}
|
|
}
|
|
else if (this->BadPoints)
|
|
{
|
|
this->BadPoints->Delete();
|
|
this->BadPoints = NULL;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::CalculateBounds(double bounds[4])
|
|
{
|
|
// We can use the BadPoints array to skip the bad points
|
|
if (!this->Points)
|
|
{
|
|
return;
|
|
}
|
|
this->CalculateUnscaledInputBounds();
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
bounds[i] = this->UnscaledInputBounds[i];
|
|
}
|
|
if (this->LogX)
|
|
{
|
|
bounds[0] = log10(bounds[0]);
|
|
bounds[1] = log10(bounds[1]);
|
|
}
|
|
if (this->LogY)
|
|
{
|
|
bounds[2] = log10(bounds[2]);
|
|
bounds[3] = log10(bounds[3]);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::SetLookupTable(vtkScalarsToColors *lut)
|
|
{
|
|
if ( this->LookupTable != lut )
|
|
{
|
|
if ( this->LookupTable)
|
|
{
|
|
this->LookupTable->UnRegister(this);
|
|
}
|
|
this->LookupTable = lut;
|
|
if (lut)
|
|
{
|
|
lut->Register(this);
|
|
}
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkScalarsToColors *vtkPlotPoints::GetLookupTable()
|
|
{
|
|
if ( this->LookupTable == 0 )
|
|
{
|
|
this->CreateDefaultLookupTable();
|
|
}
|
|
return this->LookupTable;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::CreateDefaultLookupTable()
|
|
{
|
|
if ( this->LookupTable)
|
|
{
|
|
this->LookupTable->UnRegister(this);
|
|
}
|
|
this->LookupTable = vtkLookupTable::New();
|
|
// Consistent Register/UnRegisters.
|
|
this->LookupTable->Register(this);
|
|
this->LookupTable->Delete();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::SelectColorArray(const vtkStdString& arrayName)
|
|
{
|
|
vtkTable *table = this->Data->GetInput();
|
|
if (!table)
|
|
{
|
|
vtkDebugMacro(<< "SelectColorArray called with no input table set.");
|
|
return;
|
|
}
|
|
if (this->ColorArrayName == arrayName)
|
|
{
|
|
return;
|
|
}
|
|
for (vtkIdType c = 0; c < table->GetNumberOfColumns(); ++c)
|
|
{
|
|
if (arrayName == table->GetColumnName(c))
|
|
{
|
|
this->ColorArrayName = arrayName;
|
|
this->Modified();
|
|
return;
|
|
}
|
|
}
|
|
vtkDebugMacro(<< "SelectColorArray called with invalid column name.");
|
|
this->ColorArrayName = "";
|
|
this->Modified();
|
|
return;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::SelectColorArray(vtkIdType arrayNum)
|
|
{
|
|
vtkTable *table = this->Data->GetInput();
|
|
if (!table)
|
|
{
|
|
vtkDebugMacro(<< "SelectColorArray called with no input table set.");
|
|
return;
|
|
}
|
|
vtkDataArray *col = vtkDataArray::SafeDownCast(table->GetColumn(arrayNum));
|
|
// TODO: Should add support for categorical coloring & try enum lookup
|
|
if (!col)
|
|
{
|
|
vtkDebugMacro(<< "SelectColorArray called with invalid column index");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
const char *arrayName = table->GetColumnName(arrayNum);
|
|
if (this->ColorArrayName == arrayName || arrayName == 0)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
this->ColorArrayName = arrayName;
|
|
this->Modified();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkStdString vtkPlotPoints::GetColorArrayName()
|
|
{
|
|
return this->ColorArrayName;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotPoints::PrintSelf(ostream &os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
}
|