Commit 546d6c7a authored by Brian Helba's avatar Brian Helba Committed by Marcus D. Hanwell
Browse files

ENH: Added Orientation property to vtkChartBar

Default orientation (VERTICAL) is the existing functionality.
New HORIZONTAL orientation has X-axis oriented up-down and
bar values growing left-right.

Change-Id: I00fbf3b7c4ebf0b0e589eaecdfb2bc31fcc4651a
parent 9d3bfe67
......@@ -14,6 +14,7 @@ IF (VTK_USE_RENDERING AND VTK_USE_VIEWS)
SET(MyTests ${MyTests}
#TestContextUnicode.cxx # Disabled until Freetype unicode works
TestBarGraph.cxx
TestBarGraphHorizontal.cxx
TestContext.cxx
TestContextImage.cxx
TestDiagram.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestBarGraphHorizontal.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 "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkSmartPointer.h"
#include "vtkChartXY.h"
#include "vtkPlot.h"
#include "vtkPlotBar.h"
#include "vtkTable.h"
#include "vtkIntArray.h"
#include "vtkContextView.h"
#include "vtkContextScene.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRegressionTestImage.h"
#include "vtkNew.h"
// Monthly circulation data
static int data_2008[] = {10822, 10941, 9979, 10370, 9460, 11228,
15093, 12231, 10160, 9816, 9384, 7892};
static int data_2009[] = {9058, 9474, 9979, 9408, 8900, 11569,
14688, 12231, 10294, 9585, 8957, 8590};
static int data_2010[] = {9058, 10941, 9979, 10270, 8900, 11228,
14688, 12231, 10160, 9585, 9384, 8590};
//----------------------------------------------------------------------------
int TestBarGraphHorizontal(int , char * [])
{
// Set up a 2D scene, add an XY chart to it
vtkNew<vtkContextView> view;
view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
view->GetRenderWindow()->SetSize(400, 300);
vtkNew<vtkChartXY> chart;
view->GetScene()->AddItem(chart.GetPointer());
// Create a table with some points in it...
vtkNew<vtkTable> table;
vtkNew<vtkIntArray> arrMonth;
arrMonth->SetName("Month");
table->AddColumn(arrMonth.GetPointer());
vtkNew<vtkIntArray> arr2008;
arr2008->SetName("2008");
table->AddColumn(arr2008.GetPointer());
vtkNew<vtkIntArray> arr2009;
arr2009->SetName("2009");
table->AddColumn(arr2009.GetPointer());
vtkNew<vtkIntArray> arr2010;
arr2010->SetName("2010");
table->AddColumn(arr2010.GetPointer());
table->SetNumberOfRows(12);
for (int i = 0; i < 12; i++)
{
table->SetValue(i,0,i+1);
table->SetValue(i,1,data_2008[i]);
table->SetValue(i,2,data_2009[i]);
table->SetValue(i,3,data_2010[i]);
}
// Add multiple bar plots, setting the colors etc
vtkPlot *plot = 0;
vtkPlotBar* barPlot = 0;
plot = chart->AddPlot(vtkChart::BAR);
barPlot = vtkPlotBar::SafeDownCast(barPlot);
barPlot->SetInput(table.GetPointer(), 0, 1);
barPlot->SetOrientation(vtkPlotBar::HORIZONTAL);
barPlot->SetColor(0, 255, 0, 255);
plot = chart->AddPlot(vtkChart::BAR);
barPlot = vtkPlotBar::SafeDownCast(barPlot);
barPlot->SetInput(table.GetPointer(), 0, 2);
barPlot->SetOrientation(vtkPlotBar::HORIZONTAL);
barPlot->SetColor(255, 0, 0, 255);
plot = chart->AddPlot(vtkChart::BAR);
barPlot = vtkPlotBar::SafeDownCast(barPlot);
barPlot->SetInput(table.GetPointer(), 0, 3);
barPlot->SetOrientation(vtkPlotBar::HORIZONTAL);
barPlot->SetColor(0, 0, 255, 255);
// Finally render the scene and compare the image to a reference image
view->GetRenderWindow()->SetMultiSamples(0);
view->GetInteractor()->Initialize();
view->GetInteractor()->Start();
return EXIT_SUCCESS;
}
......@@ -146,7 +146,7 @@ class vtkPlotBarSegment : public vtkObject {
}
void Paint(vtkContext2D *painter, vtkPen *pen, vtkBrush *brush,
float width, float offset)
float width, float offset, int orientation)
{
painter->ApplyPen(pen);
painter->ApplyBrush(brush);
......@@ -160,17 +160,29 @@ class vtkPlotBarSegment : public vtkObject {
for (int i = 0; i < n; ++i)
{
if (p)
painter->DrawRect(f[2*i]-(width/2)-offset, p[2*i+1],
width, f[2*i+1] - p[2*i+1]);
else
painter->DrawRect(f[2*i]-(width/2)-offset, 0.0,
width, f[2*i+1]);
if (orientation != vtkPlotBar::VERTICAL) // Also default fallback
{
if (p)
painter->DrawRect(f[2*i]-(width/2)-offset, p[2*i+1],
width, f[2*i+1] - p[2*i+1]);
else
painter->DrawRect(f[2*i]-(width/2)-offset, 0.0,
width, f[2*i+1]);
}
else // HORIZONTAL orientation
{
if (p)
painter->DrawRect(p[2*i+1], f[2*i]-(width/2)-offset,
f[2*i+1] - p[2*i+1], width);
else
painter->DrawRect(0.0, f[2*i]-(width/2)-offset,
f[2*i+1], width);
}
}
}
bool GetNearestPoint(const vtkVector2f& point, vtkVector2f* location,
float width, float offset)
float width, float offset, int orientation)
{
if (!this->Points)
{
......@@ -200,6 +212,21 @@ class vtkPlotBarSegment : public vtkObject {
// side of the point with which it is associated.
float halfWidth = width / 2.0;
// If orientation is VERTICAL, search normally. For HORIZONTAL,
// simply transpose the X and Y coordinates of the target, as the rest
// of the search uses the assumption that X = bar position, Y = bar
// value; swapping the target X and Y is simpler that swapping the
// X and Y of all the other references to the bar data.
vtkVector2f targetPoint;
if (orientation != vtkPlotBar::VERTICAL) // Also default fallback
{
targetPoint.Set(point.X(), point.Y()); // Copy
}
else // HORIZONTAL orientation
{
targetPoint.Set(point.Y(), point.X()); // Swap x and y
}
// Set up our search array, use the STL lower_bound algorithm
// When searching, invert the behavior of the offset and
// compensate for the half width overlap.
......@@ -260,7 +287,8 @@ public:
}
void PaintSegments(vtkContext2D *painter, vtkColorSeries *colorSeries,
vtkPen *pen, vtkBrush *brush, float width, float offset)
vtkPen *pen, vtkBrush *brush, float width, float offset,
int orientation)
{
int colorInSeries = 0;
bool useColorSeries = this->Segments.size() > 1;
......@@ -271,19 +299,19 @@ public:
{
brush->SetColor(colorSeries->GetColorRepeating(colorInSeries++).GetData());
}
(*it)->Paint(painter, pen, brush, width, offset);
(*it)->Paint(painter, pen, brush, width, offset, orientation);
}
}
int GetNearestPoint(const vtkVector2f& point, vtkVector2f* location,
float width, float offset)
float width, float offset, int orientation)
{
int index = 0;
for (std::vector<vtkSmartPointer<vtkPlotBarSegment> >::iterator it =
this->Segments.begin(); it != this->Segments.end(); ++it)
{
if ((*it)->GetNearestPoint(point,location,width,offset))
if ((*it)->GetNearestPoint(point,location,width,offset,orientation))
{
return index;
}
......@@ -313,6 +341,7 @@ vtkPlotBar::vtkPlotBar()
this->Pen->SetWidth(1.0);
this->Offset = 1.0;
this->ColorSeries = 0;
this->Orientation = vtkPlotBar::VERTICAL;
}
//-----------------------------------------------------------------------------
......@@ -363,7 +392,7 @@ bool vtkPlotBar::Paint(vtkContext2D *painter)
}
this->Private->PaintSegments(painter,this->ColorSeries, this->Pen,this->Brush,
this->Width, this->Offset);
this->Width, this->Offset, this->Orientation);
return true;
}
......@@ -387,6 +416,22 @@ bool vtkPlotBar::PaintLegend(vtkContext2D *painter, const vtkRectf& rect,
//-----------------------------------------------------------------------------
void vtkPlotBar::GetBounds(double bounds[4])
{
int seriesLow, seriesHigh, valuesLow, valuesHigh;
if (this->Orientation != vtkPlotBar::VERTICAL) // Also default fallback
{
seriesLow = 0; // Xmin
seriesHigh = 1; // Xmax
valuesLow = 2; // Ymin
valuesHigh = 3; // Ymax
}
else // HORIZONTAL orientation
{
seriesLow = 2; // Ymin
seriesHigh = 3; // Ymax
valuesLow = 0; // Xmin
valuesHigh = 1; // Xmax
}
// Get the x and y arrays (index 0 and 1 respectively)
vtkTable *table = this->Data->GetInput();
vtkDataArray* x = this->UseIndexForXSeries ?
......@@ -395,18 +440,18 @@ void vtkPlotBar::GetBounds(double bounds[4])
if (this->UseIndexForXSeries && y)
{
bounds[0] = 0 - (this->Width / 2 );
bounds[1] = y->GetNumberOfTuples() + (this->Width/2);
bounds[seriesLow] = 0 - (this->Width / 2 );
bounds[seriesHigh] = y->GetNumberOfTuples() + (this->Width/2);
}
else if (x && y)
{
x->GetRange(&bounds[0]);
x->GetRange(&bounds[seriesLow]);
// We surround our point by Width/2 on either side
bounds[0] -= this->Width / 2.0 + this->Offset;
bounds[1] += this->Width / 2.0 - this->Offset;
bounds[seriesLow] -= this->Width / 2.0 + this->Offset;
bounds[seriesHigh] += this->Width / 2.0 - this->Offset;
}
y->GetRange(&bounds[2]);
y->GetRange(&bounds[valuesLow]);
double y_range[2];
std::map< int, std::string >::iterator it;
......@@ -415,22 +460,33 @@ void vtkPlotBar::GetBounds(double bounds[4])
{
y = vtkDataArray::SafeDownCast(table->GetColumnByName((*it).second.c_str()));
y->GetRange(y_range);
bounds[3] += y_range[1];
bounds[valuesHigh] += y_range[1];
}
// Bar plots always have one of the y bounds at the orgin
if (bounds[2] > 0.0f)
// Bar plots always have one of the value bounds at the orgin
if (bounds[valuesLow] > 0.0f)
{
bounds[2] = 0.0;
bounds[valuesLow] = 0.0;
}
else if (bounds[3] < 0.0f)
else if (bounds[valuesHigh] < 0.0f)
{
bounds[3] = 0.0;
bounds[valuesHigh] = 0.0;
}
vtkDebugMacro(<< "Bounds: " << bounds[0] << "\t" << bounds[1] << "\t"
<< bounds[2] << "\t" << bounds[3]);
}
//-----------------------------------------------------------------------------
void vtkPlotBar::SetOrientation(int orientation)
{
if (orientation < 0 || orientation > 1)
{
vtkErrorMacro("Error, invalid orientation value supplied: " << orientation)
return;
}
this->Orientation = orientation;
}
//-----------------------------------------------------------------------------
void vtkPlotBar::SetWidth(float width)
{
......@@ -468,7 +524,7 @@ int vtkPlotBar::GetNearestPoint(const vtkVector2f& point,
vtkVector2f* location)
{
return this->Private->GetNearestPoint(point, location, this->Width,
this->Offset);
this->Offset, this->Orientation);
}
//-----------------------------------------------------------------------------
......
......@@ -39,6 +39,13 @@ public:
vtkTypeMacro(vtkPlotBar, vtkPlot);
virtual void PrintSelf(ostream &os, vtkIndent indent);
// Description:
// Enum of bar chart oritentation types
enum {
VERTICAL = 0,
HORIZONTAL
};
// Description:
// Creates a 2D Chart object.
static vtkPlotBar *New();
......@@ -73,6 +80,12 @@ public:
vtkSetMacro(Offset, float);
vtkGetMacro(Offset, float);
// Description:
// Set/get the orientation of the bars.
// Valid orientations are VERTICAL (default) and HORIZONTAL.
virtual void SetOrientation(int orientation);
vtkGetMacro(Orientation, int);
// Description:
// Get the bounds for this mapper as (Xmin,Xmax,Ymin,Ymax).
virtual void GetBounds(double bounds[4]);
......@@ -127,6 +140,8 @@ protected:
float Width;
float Offset;
int Orientation;
// Description:
// The point cache is marked dirty until it has been initialized.
vtkTimeStamp BuildTime;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment