mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
433 lines
12 KiB
C++
433 lines
12 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkPlotBox.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 "vtkPlotBox.h"
|
|
|
|
#include "vtkAbstractArray.h"
|
|
#include "vtkAxis.h"
|
|
#include "vtkBrush.h"
|
|
#include "vtkChartBox.h"
|
|
#include "vtkContext2D.h"
|
|
#include "vtkContextDevice2D.h"
|
|
#include "vtkContextMapper2D.h"
|
|
#include "vtkDataArray.h"
|
|
#include "vtkDataSetAttributes.h"
|
|
#include "vtkDoubleArray.h"
|
|
#include "vtkIdTypeArray.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkLookupTable.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPen.h"
|
|
#include "vtkNew.h"
|
|
#include "vtkScalarsToColors.h"
|
|
#include "vtkStringArray.h"
|
|
#include "vtkTable.h"
|
|
#include "vtkTextProperty.h"
|
|
#include "vtkTimeStamp.h"
|
|
#include "vtkUnsignedCharArray.h"
|
|
#include "vtkVector.h"
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
class vtkPlotBox::Private :
|
|
public std::vector< std::vector<double> >
|
|
{
|
|
public:
|
|
Private()
|
|
{
|
|
}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkStandardNewMacro(vtkPlotBox)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkPlotBox::vtkPlotBox()
|
|
{
|
|
this->Storage = new vtkPlotBox::Private();
|
|
this->Pen->SetColor(0, 0, 0);
|
|
this->BoxWidth = 20.;
|
|
this->LookupTable = 0;
|
|
this->TooltipDefaultLabelFormat = "%y";
|
|
|
|
this->TitleProperties = vtkTextProperty::New();
|
|
this->TitleProperties->SetColor(0.0, 0.0, 0.0);
|
|
this->TitleProperties->SetFontSize(12);
|
|
this->TitleProperties->SetFontFamilyToArial();
|
|
this->TitleProperties->SetBold(1);
|
|
this->TitleProperties->SetJustificationToCentered();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkPlotBox::~vtkPlotBox()
|
|
{
|
|
delete this->Storage;
|
|
|
|
if (this->LookupTable)
|
|
{
|
|
this->LookupTable->UnRegister(this);
|
|
}
|
|
|
|
|
|
this->TitleProperties->Delete();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::Update()
|
|
{
|
|
if (!this->Visible)
|
|
{
|
|
return;
|
|
}
|
|
// Check if we have an input
|
|
vtkTable *table = this->Data->GetInput();
|
|
if (!table)
|
|
{
|
|
vtkDebugMacro(<< "Update event called with no input table set.");
|
|
return;
|
|
}
|
|
|
|
this->UpdateTableCache(table);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotBox::Paint(vtkContext2D *painter)
|
|
{
|
|
// This is where everything should be drawn, or dispatched to other methods.
|
|
vtkDebugMacro(<< "Paint event called in vtkPlotBox.");
|
|
|
|
if (!this->Visible)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (this->Storage->size() == 0 || this->Storage->at(0).size() < 5)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vtkChartBox *parent = vtkChartBox::SafeDownCast(this->Parent);
|
|
|
|
int nbCols = static_cast<int>(this->Storage->size());
|
|
for (int i = 0; i < nbCols; i++)
|
|
{
|
|
vtkStdString colName = parent->GetVisibleColumns()->GetValue(i);
|
|
int index;
|
|
this->GetInput()->GetRowData()->GetAbstractArray(colName.c_str(), index);
|
|
double rgb[4];
|
|
this->LookupTable->GetIndexedColor(index, rgb);
|
|
unsigned char crgba[4] =
|
|
{
|
|
static_cast<unsigned char>(rgb[0] * 255.),
|
|
static_cast<unsigned char>(rgb[1] * 255.),
|
|
static_cast<unsigned char>(rgb[2] * 255.),
|
|
255
|
|
};
|
|
|
|
if (parent->GetSelectedColumn() == i)
|
|
{
|
|
crgba[0] = crgba[0]^255;
|
|
crgba[1] = crgba[1]^255;
|
|
crgba[2] = crgba[2]^255;
|
|
}
|
|
DrawBoxPlot(i, crgba, parent->GetXPosition(i), painter);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::DrawBoxPlot(int i, unsigned char *rgba, double x,
|
|
vtkContext2D *painter)
|
|
{
|
|
std::vector<double>& colQuartiles = this->Storage->at(i);
|
|
if (colQuartiles.size() < 5)
|
|
{
|
|
return;
|
|
}
|
|
|
|
painter->ApplyPen(this->Pen);
|
|
|
|
vtkNew<vtkBrush> brush;
|
|
brush->SetColor(rgba);
|
|
painter->ApplyBrush(brush.GetPointer());
|
|
|
|
// Helper variables for x position
|
|
double xpos = x + 0.5 * this->BoxWidth;
|
|
double xneg = x - 0.5 * this->BoxWidth;
|
|
double hBoxW = this->BoxWidth * 0.25;
|
|
|
|
// Fetch the quartiles and median
|
|
double* q = &colQuartiles[0];
|
|
|
|
// Draw the box
|
|
painter->DrawQuad(xpos, q[1], xneg, q[1], xneg, q[3], xpos, q[3]);
|
|
|
|
// Draw the whiskers: ends of the whiskers match the
|
|
// extremum values of the quartiles
|
|
painter->DrawLine(x, q[0], x, q[1]);
|
|
painter->DrawLine(x - hBoxW, q[0], x + hBoxW, q[0]);
|
|
painter->DrawLine(x, q[3], x, q[4]);
|
|
painter->DrawLine(x - hBoxW, q[4], x + hBoxW, q[4]);
|
|
|
|
// Draw the median
|
|
vtkNew<vtkPen> whitePen;
|
|
unsigned char brushColor[4];
|
|
brush->GetColor(brushColor);
|
|
// Use a gray pen if the brush is black so the median is always visible
|
|
if (brushColor[0] == 0 && brushColor[1] == 0 && brushColor[2] == 0)
|
|
{
|
|
whitePen->SetWidth(this->Pen->GetWidth());
|
|
whitePen->SetColor(128, 128, 128, 128);
|
|
whitePen->SetOpacity(this->Pen->GetOpacity());
|
|
painter->ApplyPen(whitePen.GetPointer());
|
|
}
|
|
|
|
painter->DrawLine(xneg, q[2], xpos, q[2]);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkStringArray* vtkPlotBox::GetLabels()
|
|
{
|
|
if (this->Labels)
|
|
{
|
|
return this->Labels;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotBox::PaintLegend(vtkContext2D* painter, const vtkRectf& rec, int)
|
|
{
|
|
if (this->Storage->size() == 0 || this->Storage->at(0).size() < 5)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vtkChartBox *parent = vtkChartBox::SafeDownCast(this->Parent);
|
|
|
|
painter->ApplyTextProp(this->TitleProperties);
|
|
|
|
int nbCols = static_cast<int>(this->Storage->size());
|
|
for (int i = 0; i < nbCols; i++)
|
|
{
|
|
vtkStdString colName = parent->GetVisibleColumns()->GetValue(i);
|
|
if (this->GetLabels() && this->GetLabels()->GetNumberOfValues() > i)
|
|
{
|
|
colName = this->GetLabels()->GetValue(parent->GetColumnId(colName));
|
|
}
|
|
painter->DrawString(parent->GetXPosition(i), rec.GetY(), colName);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::SetInputData(vtkTable* table)
|
|
{
|
|
if (table == this->Data->GetInput() &&
|
|
(!table || table->GetMTime() < this->BuildTime))
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->vtkPlot::SetInputData(table);
|
|
|
|
bool updateVisibility = table != this->Data->GetInput();
|
|
vtkChartBox *parent = vtkChartBox::SafeDownCast(this->Parent);
|
|
|
|
if (parent && table && updateVisibility)
|
|
{
|
|
parent->SetColumnVisibilityAll(false);
|
|
// By default make the first 10 columns visible in a plot.
|
|
for (vtkIdType i = 0; i < table->GetNumberOfColumns() && i < 10; ++i)
|
|
{
|
|
parent->SetColumnVisibility(table->GetColumnName(i), true);
|
|
}
|
|
}
|
|
else if (parent && updateVisibility)
|
|
{
|
|
// No table, therefore no visible columns
|
|
parent->GetVisibleColumns()->SetNumberOfTuples(0);
|
|
}
|
|
// Create a default lookup table is non set yet
|
|
if (!this->LookupTable)
|
|
{
|
|
this->CreateDefaultLookupTable();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace
|
|
{
|
|
// See if the point is within tolerance.
|
|
bool inRange(const vtkVector2f& point, const vtkVector2f& tol,
|
|
const vtkVector2f& current)
|
|
{
|
|
return current.GetX() > point.GetX() - tol.GetX() &&
|
|
current.GetX() < point.GetX() + tol.GetX() &&
|
|
current.GetY() > point.GetY() - tol.GetY() &&
|
|
current.GetY() < point.GetY() + tol.GetY();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkIdType vtkPlotBox::GetNearestPoint(const vtkVector2f& point,
|
|
const vtkVector2f& tol,
|
|
vtkVector2f* location)
|
|
{
|
|
vtkChartBox *parent = vtkChartBox::SafeDownCast(this->Parent);
|
|
|
|
int nbCols = static_cast<int>(this->Storage->size());
|
|
for (int i = 0; i < nbCols; i++)
|
|
{
|
|
vtkVector2f v;
|
|
v.SetX(parent->GetXPosition(i));
|
|
for (int j = 0; j < 5; j++)
|
|
{
|
|
v.SetY((*this->Storage)[i][j]);
|
|
if (inRange(point, tol, v))
|
|
{
|
|
vtkAxis* axis = parent->GetYAxis();
|
|
double min = axis->GetUnscaledMinimum();
|
|
double max = axis->GetUnscaledMaximum();
|
|
double scale = 1.0f / (max - min);
|
|
double y = (*this->Storage)[i][j] / scale + min;
|
|
location->SetX(i);
|
|
location->SetY(y);
|
|
return static_cast<int>(i);
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
bool vtkPlotBox::UpdateTableCache(vtkTable *table)
|
|
{
|
|
// Each boxplot is a column in our storage array,
|
|
// they are scaled from 0.0 to 1.0
|
|
vtkChartBox *parent = vtkChartBox::SafeDownCast(this->Parent);
|
|
|
|
if (!parent || !table || table->GetNumberOfColumns() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vtkStringArray* cols = parent->GetVisibleColumns();
|
|
|
|
this->Storage->resize(cols->GetNumberOfTuples());
|
|
vtkIdType rows = table->GetNumberOfRows();
|
|
|
|
for (vtkIdType i = 0; i < cols->GetNumberOfTuples(); ++i)
|
|
{
|
|
std::vector<double>& col = this->Storage->at(i);
|
|
col.resize(rows);
|
|
vtkSmartPointer<vtkDataArray> data =
|
|
vtkDataArray::SafeDownCast(table->GetColumnByName(cols->GetValue(i)));
|
|
if (!data)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
vtkAxis* axis = parent->GetYAxis();
|
|
// Also need the range from the appropriate axis, to normalize points
|
|
double min = axis->GetUnscaledMinimum();
|
|
double max = axis->GetUnscaledMaximum();
|
|
double scale = 1.0f / (max - min);
|
|
|
|
for (vtkIdType j = 0; j < rows; ++j)
|
|
{
|
|
col[j] = (data->GetTuple1(j) - min) * scale;
|
|
}
|
|
std::sort(col.begin(), col.end());
|
|
}
|
|
|
|
this->BuildTime.Modified();
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::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 *vtkPlotBox::GetLookupTable()
|
|
{
|
|
if (this->LookupTable == 0)
|
|
{
|
|
this->CreateDefaultLookupTable();
|
|
}
|
|
return this->LookupTable;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::SetColumnColor(const vtkStdString& colName, double *rgb)
|
|
{
|
|
if (this->LookupTable == 0)
|
|
{
|
|
this->CreateDefaultLookupTable();
|
|
}
|
|
int index;
|
|
this->GetInput()->GetRowData()->GetAbstractArray(colName.c_str(), index);
|
|
vtkLookupTable* lut = vtkLookupTable::SafeDownCast(this->LookupTable);
|
|
if (index >= 0 && lut)
|
|
{
|
|
lut->SetTableValue(index, rgb[0], rgb[1], rgb[2]);
|
|
lut->Build();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::CreateDefaultLookupTable()
|
|
{
|
|
// There must be an input to create a lookup table
|
|
if (this->GetInput())
|
|
{
|
|
if (this->LookupTable)
|
|
{
|
|
this->LookupTable->UnRegister(this);
|
|
}
|
|
vtkLookupTable* lut = vtkLookupTable::New();
|
|
this->LookupTable = lut;
|
|
// Consistent Register/UnRegisters.
|
|
this->LookupTable->Register(this);
|
|
this->LookupTable->Delete();
|
|
vtkTable *table = this->GetInput();
|
|
lut->SetNumberOfColors(table->GetNumberOfColumns());
|
|
this->LookupTable->Build();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPlotBox::PrintSelf(ostream &os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
}
|