Commit f82398af authored by Marcus D. Hanwell's avatar Marcus D. Hanwell

Introduced a new chart selection mode

This commit introduces a new chart selection mode to the charts, based
on plots rather than rows. The default remains row-based selection,
where a selection in one plot causes all corresponding points in the
same row of the table to be selected in other plot objects. This
behavior was improved slightly to iterate through and accumulate
selections in all plots (rather than just using that of the last plot
which resulted in confusing behavior).

The plot based selection keeps any selection specific to a plot. The
vtkPlot object that originated a selection is stored in the PROP
property of the vtkSelectionNode, with the SOURCE property being used to
store the table the selection is on. The vtkSelection object will have a
vtkSelectionNode object for each plot with a selection on it. All of the
normal selection combination rules are applied per-plot.

The rectangle and polygon selection mode code was refactored to reduce
the amount of code duplication necessary. Two tests were introduced
allowing interactive use of the chart with row or plot based selection
using polygon selection (left mouse) or rectangle selection (right
mouse).

Change-Id: Ib739ec620b7094bcf4940767000e8620c432e341
parent 9ae3b4c1
......@@ -28,6 +28,8 @@
TestLinePlotAxisFonts.cxx
TestLinePlot2.cxx
TestLinePlotInteraction.cxx
TestLinePlotSelection.cxx
TestLinePlotSelection2.cxx
TestMultipleChartRenderers.cxx
TestMultipleRenderers.cxx
TestMultipleScalarsToColors.cxx
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestLinePlotSelection.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 "vtkRenderWindow.h"
#include "vtkSmartPointer.h"
#include "vtkChartXY.h"
#include "vtkPlot.h"
#include "vtkTable.h"
#include "vtkFloatArray.h"
#include "vtkContextView.h"
#include "vtkContextScene.h"
#include "vtkContextMouseEvent.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkAnnotationLink.h"
#include "vtkNew.h"
//----------------------------------------------------------------------------
int TestLinePlotSelection(int, char * [])
{
// Set up a 2D scene, add an XY chart to it
vtkNew<vtkContextView> view;
view->GetRenderWindow()->SetSize(400, 300);
vtkNew<vtkChartXY> chart;
view->GetScene()->AddItem(chart.GetPointer());
vtkNew<vtkAnnotationLink> link;
chart->SetAnnotationLink(link.GetPointer());
chart->SetActionToButton(vtkChart::SELECT_POLYGON,
vtkContextMouseEvent::LEFT_BUTTON);
chart->SetSelectionMethod(vtkChart::SELECTION_ROWS);
// Create a table with some points in it...
vtkNew<vtkTable> table;
vtkNew<vtkFloatArray> arrX;
arrX->SetName("X Axis");
table->AddColumn(arrX.GetPointer());
vtkNew<vtkFloatArray> arrC;
arrC->SetName("Cosine");
table->AddColumn(arrC.GetPointer());
vtkNew<vtkFloatArray> arrS;
arrS->SetName("Sine");
table->AddColumn(arrS.GetPointer());
vtkNew<vtkFloatArray> arrS2;
arrS2->SetName("Sine2");
table->AddColumn(arrS2.GetPointer());
// Test charting with a few more points...
int numPoints = 69;
float inc = 7.5 / (numPoints-1);
table->SetNumberOfRows(numPoints);
for (int i = 0; i < numPoints; ++i)
{
table->SetValue(i, 0, i * inc);
table->SetValue(i, 1, cos(i * inc) + 0.0);
table->SetValue(i, 2, sin(i * inc) + 0.0);
table->SetValue(i, 3, sin(i * inc) + 0.5);
}
// Add multiple line plots, setting the colors etc
vtkPlot *line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table.GetPointer(), 0, 1);
line->SetColor(0, 255, 0, 255);
line->SetWidth(1.0);
line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table.GetPointer(), 0, 2);
line->SetColor(255, 0, 0, 255);
line->SetWidth(5.0);
line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table.GetPointer(), 0, 3);
line->SetColor(0, 0, 255, 255);
line->SetWidth(4.0);
view->Update();
view->Render();
// Inject some mouse events to perform selection.
chart->SetSelectionMode(vtkContextScene::SELECTION_ADDITION);
vtkContextMouseEvent event;
event.SetInteractor(view->GetInteractor());
event.SetPos(vtkVector2f(80, 50));
event.SetButton(vtkContextMouseEvent::RIGHT_BUTTON);
chart->MouseButtonPressEvent(event);
event.SetPos(vtkVector2f(200, 200));
chart->MouseButtonReleaseEvent(event);
// Polygon now.
event.SetPos(vtkVector2f(260, 50));
event.SetButton(vtkContextMouseEvent::LEFT_BUTTON);
chart->MouseButtonPressEvent(event);
event.SetPos(vtkVector2f(220, 250));
chart->MouseMoveEvent(event);
event.SetPos(vtkVector2f(350, 90));
chart->MouseButtonReleaseEvent(event);
//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;
}
/*=========================================================================
Program: Visualization Toolkit
Module: TestLinePlotSelection2.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 "vtkRenderWindow.h"
#include "vtkSmartPointer.h"
#include "vtkChartXY.h"
#include "vtkPlot.h"
#include "vtkTable.h"
#include "vtkFloatArray.h"
#include "vtkContextView.h"
#include "vtkContextScene.h"
#include "vtkContextMouseEvent.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkAnnotationLink.h"
#include "vtkNew.h"
//----------------------------------------------------------------------------
int TestLinePlotSelection2(int, char * [])
{
// Set up a 2D scene, add an XY chart to it
vtkNew<vtkContextView> view;
view->GetRenderWindow()->SetSize(400, 300);
vtkNew<vtkChartXY> chart;
view->GetScene()->AddItem(chart.GetPointer());
vtkNew<vtkAnnotationLink> link;
chart->SetAnnotationLink(link.GetPointer());
chart->SetActionToButton(vtkChart::SELECT_POLYGON,
vtkContextMouseEvent::LEFT_BUTTON);
chart->SetSelectionMethod(vtkChart::SELECTION_PLOTS);
// Create a table with some points in it...
vtkNew<vtkTable> table;
vtkNew<vtkFloatArray> arrX;
arrX->SetName("X Axis");
table->AddColumn(arrX.GetPointer());
vtkNew<vtkFloatArray> arrC;
arrC->SetName("Cosine");
table->AddColumn(arrC.GetPointer());
vtkNew<vtkFloatArray> arrS;
arrS->SetName("Sine");
table->AddColumn(arrS.GetPointer());
vtkNew<vtkFloatArray> arrS2;
arrS2->SetName("Sine2");
table->AddColumn(arrS2.GetPointer());
// Test charting with a few more points...
int numPoints = 69;
float inc = 7.5 / (numPoints-1);
table->SetNumberOfRows(numPoints);
for (int i = 0; i < numPoints; ++i)
{
table->SetValue(i, 0, i * inc);
table->SetValue(i, 1, cos(i * inc) + 0.0);
table->SetValue(i, 2, sin(i * inc) + 0.0);
table->SetValue(i, 3, sin(i * inc) + 0.5);
}
// Add multiple line plots, setting the colors etc
vtkPlot *line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table.GetPointer(), 0, 1);
line->SetColor(0, 255, 0, 255);
line->SetWidth(1.0);
line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table.GetPointer(), 0, 2);
line->SetColor(255, 0, 0, 255);
line->SetWidth(5.0);
line = chart->AddPlot(vtkChart::LINE);
line->SetInputData(table.GetPointer(), 0, 3);
line->SetColor(0, 0, 255, 255);
line->SetWidth(4.0);
view->Update();
view->Render();
// Inject some mouse events to perform selection.
chart->SetSelectionMode(vtkContextScene::SELECTION_ADDITION);
vtkContextMouseEvent event;
event.SetInteractor(view->GetInteractor());
event.SetPos(vtkVector2f(80, 50));
event.SetButton(vtkContextMouseEvent::RIGHT_BUTTON);
chart->MouseButtonPressEvent(event);
event.SetPos(vtkVector2f(200, 200));
chart->MouseButtonReleaseEvent(event);
// Polygon now.
event.SetPos(vtkVector2f(260, 50));
event.SetButton(vtkContextMouseEvent::LEFT_BUTTON);
chart->MouseButtonPressEvent(event);
event.SetPos(vtkVector2f(220, 250));
chart->MouseMoveEvent(event);
event.SetPos(vtkVector2f(350, 90));
chart->MouseButtonReleaseEvent(event);
//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;
}
......@@ -65,6 +65,7 @@ vtkChart::vtkChart()
this->BackgroundBrush = vtkSmartPointer<vtkBrush>::New();
this->BackgroundBrush->SetColorF(1, 1, 1, 0);
this->SelectionMode = vtkContextScene::SELECTION_NONE;
this->SelectionMethod = vtkChart::SELECTION_ROWS;
}
//-----------------------------------------------------------------------------
......@@ -153,6 +154,24 @@ void vtkChart::RecalculateBounds()
{
return;
}
//-----------------------------------------------------------------------------
void vtkChart::SetSelectionMethod(int method)
{
if (method == this->SelectionMethod)
{
return;
}
this->SelectionMethod = method;
this->Modified();
}
//-----------------------------------------------------------------------------
int vtkChart::GetSelectionMethod()
{
return this->SelectionMethod;
}
//-----------------------------------------------------------------------------
void vtkChart::SetShowLegend(bool visible)
{
......
......@@ -120,6 +120,25 @@ public:
// useful in applications after the parameters of plots have been modified.
virtual void RecalculateBounds();
// Description:
// Enumeration of the possible selection methods in a chart. SELECTION_ROWS
// is the default and simply selects the row in a table in all plots showing
// that table. SELECTION_PLOTS will make a selection in each plot, and that
// selection remains specific to the plot object.
enum {
SELECTION_ROWS,
SELECTION_PLOTS
};
// Description:
// Set the selection method, which controls how selections are handled by the
// chart. The default is SELECTION_ROWS which selects all points in all plots
// in a chart that have values in the rows selected. SELECTION_PLOTS allows
// for finer-grained selections specific to each plot, and so to each XY
// column pair.
virtual void SetSelectionMethod(int method);
virtual int GetSelectionMethod();
// Description:
// Set the vtkAnnotationLink for the chart.
virtual void SetAnnotationLink(vtkAnnotationLink *link);
......@@ -319,6 +338,10 @@ protected:
// The mode when the chart is doing selection.
int SelectionMode;
// How plot selections are handled, SELECTION_ROWS (default) or
// SELECTION_PLOTS - based on the plot that created the selection.
int SelectionMethod;
// Description:
// Hold mouse action mappings.
class MouseActions
......
......@@ -25,12 +25,16 @@
#define __vtkChartSelectionHelper_h
#include "vtkNew.h"
#include "vtkSmartPointer.h"
#include "vtkAnnotationLink.h"
#include "vtkSelection.h"
#include "vtkSelectionNode.h"
#include "vtkIdTypeArray.h"
#include "vtkContextScene.h"
#include "vtkContextMouseEvent.h"
#include "vtkInformation.h"
#include "vtkPlot.h"
#include "vtkTable.h"
#include <vector>
#include <algorithm>
......@@ -41,17 +45,49 @@ namespace vtkChartSelectionHelper
// Description:
// Populate the annotation link with the supplied selectionIds array, and set
// the appropriate node properties for a standard row based chart selection.
void MakeSelection(vtkAnnotationLink *link, vtkIdTypeArray *selectionIds)
void MakeSelection(vtkAnnotationLink *link, vtkIdTypeArray *selectionIds,
vtkPlot *plot)
{
assert(link != NULL && selectionIds != NULL);
vtkNew<vtkSelection> selection;
vtkNew<vtkSelectionNode> node;
selection->AddNode(node.GetPointer());
node->SetContentType(vtkSelectionNode::INDICES);
node->SetFieldType(vtkSelectionNode::POINT);
node->SetSelectionList(selectionIds);
link->SetCurrentSelection(selection.GetPointer());
if (plot)
{
// We are building up plot-based selections, using multiple nodes.
vtkSelection *selection = link->GetCurrentSelection();
vtkSmartPointer<vtkSelectionNode> node;
for (unsigned int i = 0; i < selection->GetNumberOfNodes(); ++i)
{
vtkSelectionNode *tmp = selection->GetNode(i);
vtkPlot *selectionPlot =
vtkPlot::SafeDownCast(tmp->GetProperties()->Get(vtkSelectionNode::PROP()));
if (selectionPlot == plot)
{
node = tmp;
break;
}
}
if (!node)
{
node = vtkSmartPointer<vtkSelectionNode>::New();
selection->AddNode(node.GetPointer());
node->SetContentType(vtkSelectionNode::INDICES);
node->SetFieldType(vtkSelectionNode::POINT);
node->GetProperties()->Set(vtkSelectionNode::PROP(), plot);
node->GetProperties()->Set(vtkSelectionNode::SOURCE(), plot->GetInput());
}
node->SetSelectionList(selectionIds);
}
else
{
// Use a simple single selection node layout, remove previous selections.
vtkNew<vtkSelection> selection;
vtkNew<vtkSelectionNode> node;
selection->AddNode(node.GetPointer());
node->SetContentType(vtkSelectionNode::INDICES);
node->SetFieldType(vtkSelectionNode::POINT);
node->SetSelectionList(selectionIds);
link->SetCurrentSelection(selection.GetPointer());
}
}
// Description:
......@@ -174,10 +210,11 @@ void ToggleSelection(vtkIdTypeArray *selection, vtkIdTypeArray *oldSelection)
// Description:
// Build a selection based on the supplied selectionMode using the new
// plotSelection and combining it with the oldSelection. If link is not void
// plotSelection and combining it with the oldSelection. If link is not NULL
// then the resulting selection will be set on the link.
void BuildSelection(vtkAnnotationLink *link, int selectionMode,
vtkIdTypeArray *plotSelection, vtkIdTypeArray *oldSelection)
vtkIdTypeArray *plotSelection, vtkIdTypeArray *oldSelection,
vtkPlot *plot)
{
if (!plotSelection || !oldSelection)
{
......@@ -204,7 +241,7 @@ void BuildSelection(vtkAnnotationLink *link, int selectionMode,
if (link)
{
MakeSelection(link, plotSelection);
MakeSelection(link, plotSelection, plot);
}
}
......
This diff is collapsed.
......@@ -121,6 +121,14 @@ public:
// useful in applications after the parameters of plots have been modified.
virtual void RecalculateBounds();
// Description:
// Set the selection method, which controls how selections are handled by the
// chart. The default is SELECTION_ROWS which selects all points in all plots
// in a chart that have values in the rows selected. SELECTION_PLOTS allows
// for finer-grained selections specific to each plot, and so to each XY
// column pair.
virtual void SetSelectionMethod(int method);
// Description:
// If true then the axes will be drawn at the origin (scientific style).
vtkSetMacro(DrawAxesAtOrigin, bool);
......@@ -318,6 +326,13 @@ private:
void ZoomInAxes(vtkAxis *x, vtkAxis *y, float *orign, float *max);
// Description:
// Transform the selection box or polygon.
void TransformBoxOrPolygon(bool polygonMode, vtkTransform2D *transform,
const vtkVector2f &mousePosition,
vtkVector2f &min, vtkVector2f &max,
vtkContextPolygon &polygon);
//ETX
};
......
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