Commit b141c22c authored by Francois Bertel's avatar Francois Bertel

ENH:Add picking with colorbuffer id on 2D API, panel and wedge marks.

parent 3c039804
......@@ -26,6 +26,7 @@ SET(Kit_SRCS
vtkColorSeries.cxx
vtkContext2D.cxx
vtkContextActor.cxx
vtkContextBufferId.cxx
vtkContextDevice2D.cxx
vtkContextItem.cxx
vtkContextMapper2D.cxx
......
......@@ -11,6 +11,7 @@ IF (VTK_USE_RENDERING AND VTK_USE_VIEWS)
TestMarks.cxx
TestMarksGanttChart.cxx
TestMarksWedge.cxx
TestMarksWedgeCallback.cxx
TestMarksWedgeLine.cxx
)
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestMarksWedgeCallback.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 "vtkWedgeMark.h"
#include "vtkBarMark.h"
#include "vtkContextScene.h"
#include "vtkContextView.h"
#include "vtkDoubleArray.h"
#include "vtkLineMark.h"
#include "vtkMarkUtil.h"
#include "vtkPanelMark.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkTable.h"
#include <functional>
#include <cassert>
#include "vtkCommand.h"
#include "vtkMath.h"
#include "vtkValueHolder.txx"
// explicit instantiation
template class vtkValueHolder<double>;
namespace
{
// Normalized the data in [0,1].
vtkDataElement DataFunction(vtkMark* vtkNotUsed(m), vtkDataElement& d)
{
vtkSmartPointer<vtkDoubleArray> a=vtkSmartPointer<vtkDoubleArray>::New();
double s=0.0;
int c=d.GetNumberOfChildren();
int i=0;
a->SetNumberOfTuples(c);
while(i<c)
{
s+=d.GetValue(i).ToDouble();
++i;
}
i=0;
while(i<c)
{
a->SetValue(i,d.GetValue(i).ToDouble()/s);
++i;
}
vtkDataElement result(a);
return result;
}
// Convert incoming data [0,1] to angles in degrees.
double AngleFunction(vtkMark* vtkNotUsed(m), vtkDataElement& d)
{
return d.GetValue().ToDouble()*360.0;
}
double LeftFunction(vtkMark *m, vtkDataElement& d)
{
vtkIdType i=m->GetIndex();
// this line assume that angle is independant of leftfunction.
// otherwise, they will be an infinite recursion.
double *angle=m->GetAngleHolder().GetArray(m);
// Compute start angle. Not efficient but the protovis sibling()
// has not to been translated into VTK Marks.
double a0=0.0;
double a1=0.0;
vtkIdType j=0;
while(j<=i)
{
a0=a1;
a1=angle[j]+a0;
++j;
}
vtkIdType o=static_cast<vtkIdType>(m->GetUserVariable("o").GetConstant());
return 175.0+cos(vtkMath::RadiansFromDegrees(a0+angle[i]/2))*(o==i ? 10 : 0);
}
double BottomFunction(vtkMark *m, vtkDataElement& d)
{
vtkIdType i=m->GetIndex();
// this line assume that angle is independant of leftfunction.
// otherwise, they will be an infinite recursion.
double *angle=m->GetAngleHolder().GetArray(m);
// Compute start angle. Not efficient but the protovis sibling()
// has not to been translated into VTK Marks.
double a0=0.0;
double a1=0.0;
vtkIdType j=0;
while(j<=i)
{
a0=a1;
a1=angle[j]+a0;
++j;
}
vtkIdType o=static_cast<vtkIdType>(m->GetUserVariable("o").GetConstant());
// protovis uses clockwise and radians.
// VTK uses counterclockwise and degrees.
return 175.0+sin(vtkMath::RadiansFromDegrees(a0+angle[i]/2))*(o==i ? 10 : 0);
}
}
class MyCommand : public vtkCommand
{
public:
static MyCommand *New()
{
return new MyCommand;
}
void Execute(vtkObject *caller, unsigned long eventId,
void *callData)
{
assert("pre: callData_exists" && callData!=0);
int sectorIndex=*static_cast<int *>(callData);
vtkWedgeMark *m=static_cast<vtkWedgeMark *>(caller);
m->SetUserVariable("o",vtkValue<double>(sectorIndex));
m->GetScene()->SetDirty(true);
}
protected:
MyCommand() {}
~MyCommand() {}
};
int TestMarksWedgeCallback(int argc, char* argv[])
{
// Set up a 2D context view, context test object and add it to the scene
vtkSmartPointer<vtkContextView> view =
vtkSmartPointer<vtkContextView>::New();
view->GetRenderer()->SetBackground(0.5, 0.0, 0.2);
view->GetRenderWindow()->SetSize(400, 400);
view->GetRenderWindow()->SetMultiSamples(0);
vtkSmartPointer<vtkTable> t = vtkSmartPointer<vtkTable>::New();
vtkSmartPointer<vtkDoubleArray> arr1 =
vtkSmartPointer<vtkDoubleArray>::New();
arr1->SetName("Array1");
double input[]={1, 1.2, 1.7, 1.5, .7};
for (vtkIdType i = 0; i < 5; ++i)
{
arr1->InsertNextValue(input[i]);
}
t->AddColumn(arr1);
vtkDataElement data(t);
data.SetDimension(1); // ??
vtkSmartPointer<vtkPanelMark> panel = vtkSmartPointer<vtkPanelMark>::New();
view->GetScene()->AddItem(panel);
panel->SetData(data);
panel->SetLeft(2);
panel->SetBottom(2);
panel->SetWidth(150);
panel->SetHeight(150);
vtkMark *wedge=panel->Add(vtkMark::WEDGE);
wedge->SetData(DataFunction);
wedge->SetLeft(LeftFunction); // 175.0
wedge->SetBottom(BottomFunction); // 175.0
wedge->SetLineWidth(0.0);
wedge->SetInnerRadius(100.0);
wedge->SetOuterRadius(140.0);
wedge->SetAngle(AngleFunction);
wedge->SetLineColor(vtkColor(1.0,1.0,1.0));
wedge->SetUserVariable("o",vtkValue<double>(-1));
MyCommand *myCommand=MyCommand::New();
wedge->AddObserver(vtkCommand::EnterEvent,myCommand);
myCommand->Delete();
view->GetInteractor()->Initialize();
int retVal = vtkRegressionTestImage(view->GetRenderWindow());
if(retVal == vtkRegressionTester::DO_INTERACTOR)
{
view->GetInteractor()->Start();
}
return !retVal;
}
......@@ -29,7 +29,7 @@
#include <cassert>
vtkCxxRevisionMacro(vtkContext2D, "1.21");
vtkCxxRevisionMacro(vtkContext2D, "1.22");
//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkContext2D);
......@@ -66,6 +66,35 @@ bool vtkContext2D::End()
return true;
}
// ----------------------------------------------------------------------------
bool vtkContext2D::GetBufferIdMode() const
{
return this->BufferId!=0;
}
// ----------------------------------------------------------------------------
void vtkContext2D::BufferIdModeBegin(vtkContextBufferId *bufferId)
{
assert("pre: not_yet" && !this->GetBufferIdMode());
assert("pre: bufferId_exists" && bufferId!=0);
this->BufferId=bufferId;
this->Device->BufferIdModeBegin(bufferId);
assert("post: started" && this->GetBufferIdMode());
}
// ----------------------------------------------------------------------------
void vtkContext2D::BufferIdModeEnd()
{
assert("pre: started" && this->GetBufferIdMode());
this->Device->BufferIdModeEnd();
this->BufferId=0;
assert("post: done" && !this->GetBufferIdMode());
}
//-----------------------------------------------------------------------------
void vtkContext2D::DrawLine(float x1, float y1, float x2, float y2)
{
......@@ -136,7 +165,7 @@ void vtkContext2D::DrawPoly(float *x, float *y, int n)
void vtkContext2D::DrawPoly(vtkPoints2D *points)
{
// Construct an array with the correct coordinate packing for OpenGL.
int n = points->GetNumberOfPoints();
int n = static_cast<int>(points->GetNumberOfPoints());
// If the points are of type float then call OpenGL directly
float *f = vtkFloatArray::SafeDownCast(points->GetData())->GetPointer(0);
this->DrawPoly(f, n);
......@@ -185,7 +214,7 @@ void vtkContext2D::DrawPoints(float *x, float *y, int n)
void vtkContext2D::DrawPoints(vtkPoints2D *points)
{
// Construct an array with the correct coordinate packing for OpenGL.
int n = points->GetNumberOfPoints();
int n = static_cast<int>(points->GetNumberOfPoints());
// If the points are of type float then call OpenGL directly
float *f = vtkFloatArray::SafeDownCast(points->GetData())->GetPointer(0);
this->DrawPoints(f, n);
......@@ -356,7 +385,7 @@ void vtkContext2D::DrawStringRect(vtkPoints2D *rect, const vtkStdString &string)
}
else if (this->TextProp->GetJustification() == VTK_TEXT_CENTERED)
{
x = f[0] + 0.5*f[2];
x = f[0] + 0.5f*f[2];
}
else
{
......@@ -369,7 +398,7 @@ void vtkContext2D::DrawStringRect(vtkPoints2D *rect, const vtkStdString &string)
}
else if (this->TextProp->GetVerticalJustification() == VTK_TEXT_CENTERED)
{
y = f[1] + 0.5*f[3];
y = f[1] + 0.5f*f[3];
}
else
{
......@@ -505,10 +534,38 @@ void vtkContext2D::PopMatrix()
this->Device->PopMatrix();
}
// ----------------------------------------------------------------------------
void vtkContext2D::ApplyId(vtkIdType id)
{
assert("pre: zero_reserved_for_background" && id>0);
assert("pre: 24bit_limited" && id<16777216);
unsigned char rgba[4];
// r most significant bits (16-23).
// g (8-15)
// b less significant bits (0-7).
rgba[0]= static_cast<unsigned char>((id & 0xff0000) >> 16);
rgba[1]= static_cast<unsigned char>((id & 0xff00) >> 8);
rgba[2]= static_cast<unsigned char>(id & 0xff);
rgba[3]=1; // not used (because the colorbuffer in the default framebuffer
// may not have an alpha channel)
assert("check: valid_conversion" &&
static_cast<vtkIdType>((static_cast<int>(rgba[0])<<16)
|(static_cast<int>(rgba[1])<<8)
|static_cast<int>(rgba[2]))==id);
this->Device->SetColor4(rgba);
}
//-----------------------------------------------------------------------------
inline void vtkContext2D::ApplyPen()
{
this->Device->SetColor4(this->Pen->GetColor());
if(!this->GetBufferIdMode())
{
this->Device->SetColor4(this->Pen->GetColor());
}
this->Device->SetLineWidth(this->Pen->GetWidth());
this->Device->SetPointSize(this->Pen->GetWidth());
this->Device->SetLineType(this->Pen->GetLineType());
......@@ -517,7 +574,10 @@ inline void vtkContext2D::ApplyPen()
//-----------------------------------------------------------------------------
inline void vtkContext2D::ApplyBrush()
{
this->Device->SetColor4(this->Brush->GetColor());
if(!this->GetBufferIdMode())
{
this->Device->SetColor4(this->Brush->GetColor());
}
}
//-----------------------------------------------------------------------------
......@@ -528,6 +588,7 @@ vtkContext2D::vtkContext2D()
this->Brush = vtkBrush::New();
this->TextProp = vtkTextProperty::New();
this->Transform = NULL;
this->BufferId=0;
}
//-----------------------------------------------------------------------------
......
......@@ -37,6 +37,7 @@ class vtkPen;
class vtkBrush;
class vtkImageData;
class vtkTransform2D;
class vtkContextBufferId;
class VTK_CHARTS_EXPORT vtkContext2D : public vtkObject
{
......@@ -61,7 +62,25 @@ public:
// should be called by the destructor. Returns true if the painter is no
// longer active, otherwise false.
bool End();
// Description:
// Tell if the context is in BufferId creation mode. Initial value is false.
bool GetBufferIdMode() const;
// Description:
// Start BufferId creation Mode.
// \pre not_yet: !GetBufferIdMode()
// \pre bufferId_exists: bufferId!=0
// \post started: GetBufferIdMode()
void BufferIdModeBegin(vtkContextBufferId *bufferId);
// Description:
// Finalize BufferId creation Mode. It makes sure that the content of the
// bufferId passed in argument of BufferIdModeBegin() is correctly set.
// \pre started: GetBufferIdMode()
// \post done: !GetBufferIdMode()
void BufferIdModeEnd();
// Description:
// Draw a line between the specified points.
void DrawLine(float x1, float y1, float x2, float y2);
......@@ -220,7 +239,7 @@ public:
// Get the pen which controls the outlines of shapes as well as lines, points
// and related primitives.
vtkGetObjectMacro(Brush, vtkBrush);
// Description:
// Apply the supplied text property which controls how text is rendered.
// This makes a deep copy of the vtkTextProperty object in the vtkContext2D,
......@@ -246,6 +265,10 @@ public:
void PushMatrix();
void PopMatrix();
// Description:
// Apply id as a color.
void ApplyId(vtkIdType id);
//BTX
protected:
vtkContext2D();
......@@ -256,7 +279,9 @@ protected:
vtkBrush *Brush; // Fills
vtkTextProperty *TextProp; // Text property
vtkTransform2D *Transform; // The painter transform
vtkContextBufferId *BufferId;
private:
vtkContext2D(const vtkContext2D &); // Not implemented.
void operator=(const vtkContext2D &); // Not implemented.
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkContextBufferId.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 "vtkContextBufferId.h"
#include "vtkIntArray.h"
#include <cassert>
#include "vtkObjectFactory.h"
vtkCxxRevisionMacro(vtkContextBufferId, "1.1");
vtkStandardNewMacro(vtkContextBufferId);
// ----------------------------------------------------------------------------
vtkContextBufferId::vtkContextBufferId()
{
this->Width=0;
this->Height=0;
this->IdArray=0;
}
// ----------------------------------------------------------------------------
vtkContextBufferId::~vtkContextBufferId()
{
if(this->IdArray!=0)
{
this->IdArray->Delete();
}
}
// ----------------------------------------------------------------------------
void vtkContextBufferId::Allocate()
{
assert("pre: positive_width" && this->GetWidth()>0);
assert("pre: positive_height" && this->GetHeight()>0);
vtkIdType size=this->Width*this->Height;
if(this->IdArray!=0 && this->IdArray->GetNumberOfTuples()<size)
{
this->IdArray->Delete();
this->IdArray=0;
}
if(this->IdArray==0)
{
this->IdArray=vtkIntArray::New(); // limit to 32-bit
this->IdArray->SetNumberOfComponents(1);
this->IdArray->SetNumberOfTuples(size); // allocation
}
}
// ----------------------------------------------------------------------------
bool vtkContextBufferId::IsAllocated() const
{
return this->IdArray!=0 &&
this->IdArray->GetNumberOfTuples()>=(this->Width*this->Height);
}
// ----------------------------------------------------------------------------
void vtkContextBufferId::SetValue(vtkIdType i,
int value)
{
assert("pre: is_allocated" && this->IsAllocated());
assert("pre: valid_i" && i>=0 && i<this->GetWidth()*this->GetHeight());
this->IdArray->SetValue(i,value);
assert("post: is_set" && this->GetValue(i)==value);
}
// ----------------------------------------------------------------------------
int vtkContextBufferId::GetValue(vtkIdType i)
{
assert("pre: is_allocated" && this->IsAllocated());
assert("pre: valid_i" && i>=0 && i<this->GetWidth()*this->GetHeight());
return this->IdArray->GetValue(i);
}
// ----------------------------------------------------------------------------
vtkIdType vtkContextBufferId::GetPickedItem(int x, int y)
{
assert("pre: is_allocated" && this->IsAllocated());
vtkIdType result=-1;
if(x<0 || x>=this->Width)
{
vtkWarningMacro(<<"x mouse position out of range: x=" << x << " (width="
<< this->Width <<")");
}
else
{
if(y<0 || y>=this->Height)
{
vtkWarningMacro(<<"y mouse position out of range: y="<< y << " (height="
<< this->Height << ")");
}
else
{
result=
static_cast<vtkIdType>(this->IdArray->GetValue(y*this->Width+x))-1;
}
}
assert("post: valid_result" && result>=-1 );
return result;
}
//-----------------------------------------------------------------------------
void vtkContextBufferId::PrintSelf(ostream &os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkContextBufferId.h
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.
=========================================================================*/
// .NAME vtkContextBufferId - 2D array of ids, used for picking.
//
// .SECTION Description
// An 2D array where each element is the id of an entity drawn at the given
// pixel.
#ifndef __vtkContextBufferId_h
#define __vtkContextBufferId_h
#include "vtkObject.h"
class vtkIntArray;
class VTK_CHARTS_EXPORT vtkContextBufferId : public vtkObject
{
public:
vtkTypeRevisionMacro(vtkContextBufferId, vtkObject);
virtual void PrintSelf(ostream &os, vtkIndent indent);
// Description:
// Creates a 2D Painter object.
static vtkContextBufferId *New();
// Description:
// Number of columns. Initial value is 0.
vtkGetMacro(Width,int);
// Description:
// Set the number of columns. Initial value is 0.
vtkSetMacro(Width,int);
// Description:
// Number of rows. Initial value is 0.
vtkGetMacro(Height,int);
// Description:
// Set the number of rows. Initial value is 0.
vtkSetMacro(Height,int);
// Description:
// Allocate the memory for at least Width*Height elements.
// \pre positive_width: GetWidth()>0
// \pre positive_height: GetHeight()>0
void Allocate();
// Description:
// Tell if the buffer has been allocated.
bool IsAllocated() const;
// Description:
// Set the value at index `i'.
// \pre is_allocated: this->IsAllocated()
// \pre valid_i: i>=0 i<this->GetWidth()*this->GetHeight()
// \post is_set: this->GetValue(i)==value
void SetValue(vtkIdType i,
int value);
// Description:
// Get the value at index `i'.
// \pre is_allocated: this->IsAllocated()
// \pre valid_i: i>=0 i<this->GetWidth()*this->GetHeight()
int GetValue(vtkIdType i);
// Description:
// Return item under abscissa x and ordinate y.
// Abscissa go from left to right.
// Ordinate go from bottom to top.
// The return value is -1 if there is no item.
// \pre is_allocated: IsAllocated()
// \post valid_result: result>=-1
vtkIdType GetPickedItem(int x, int y);
protected:
vtkContextBufferId();
virtual ~vtkContextBufferId();
int Width;
int Height;
vtkIntArray *IdArray;
private:
vtkContextBufferId(const vtkContextBufferId &); // Not implemented.
void operator=(const vtkContextBufferId &); // Not implemented.
};
#endif // #ifndef __vtkContextBufferId_h
......@@ -17,8 +17,9 @@
#include "vtkContextDevice2D.h"
#include "vtkObjectFactory.h"
#include <assert.h>
vtkCxxRevisionMacro(vtkContextDevice2D, "1.1");
vtkCxxRevisionMacro(vtkContextDevice2D, "1.2");
//-----------------------------------------------------------------------------
//vtkStandardNewMacro(vtkContextDevice2D);
......@@ -26,6 +27,7 @@ vtkContextDevice2D::vtkContextDevice2D()
{
this->Geometry[0] = 0;
this->Geometry[1] = 0;
this->BufferId=0;
}
//-----------------------------------------------------------------------------
......@@ -33,6 +35,33 @@ vtkContextDevice2D::~vtkContextDevice2D()
{
}
// ----------------------------------------------------------------------------
bool vtkContextDevice2D::GetBufferIdMode() const
{
return this->BufferId!=0;
}
// ----------------------------------------------------------------------------
void vtkContextDevice2D::BufferIdModeBegin(vtkContextBufferId *bufferId)
{
assert("pre: not_yet" && !this->GetBufferIdMode());
assert("pre: bufferId_exists" && bufferId!=0);
this->BufferId=bufferId;
assert("post: started" && this->GetBufferIdMode());
}
// ----------------------------------------------------------------------------
void vtkContextDevice2D::BufferIdModeEnd()
{
assert("pre: started" && this->GetBufferIdMode());
this->BufferId=0;
assert("post: done" && !this->GetBufferIdMode());
}
//-----------------------------------------------------------------------------
void vtkContextDevice2D::PrintSelf(ostream &os, vtkIndent indent)
{
......
......@@ -32,6 +32,7 @@ class vtkTextProperty;
class vtkPoints2D;
class vtkImageData;
class vtkMatrix3x3;
class vtkContextBufferId;
class VTK_CHARTS_EXPORT vtkContextDevice2D : public vtkObject
{
......@@ -157,6 +158,27 @@ public:
// End drawing, clean up the view.
virtual void End() { }
// Description:
// Tell if the device context is in BufferId creation mode.
// Initial value is false.
virtual bool GetBufferIdMode() const;
// Description:
// Start BufferId creation Mode.
// The default implementation is empty.
// \pre not_yet: !GetBufferIdMode()
// \pre bufferId_exists: bufferId!=0
// \post started: GetBufferIdMode()
virtual void BufferIdModeBegin(vtkContextBufferId *bufferId);
// Description:
// Finalize BufferId creation Mode. It makes sure that the content of the
// bufferId passed in argument of BufferIdModeBegin() is correctly set.
// The default implementation is empty.
// \pre started: GetBufferIdMode()
// \post done: !GetBufferIdMode()
virtual void BufferIdModeEnd();
//BTX