Commit 9c0081fe authored by Julien Finet's avatar Julien Finet Committed by Marcus D. Hanwell

ENH: Improve support for control points

parent 1e980ac2
......@@ -76,7 +76,14 @@ int TestScalarsToColors( int argc, char * argv [] )
item3->SetOpacity(0.2);
item3->SetMaskAboveCurve(true);
chart->AddPlot(item3);
/*
vtkSmartPointer<vtkPiecewiseFunctionItem> item3 =
vtkSmartPointer<vtkPiecewiseFunctionItem>::New();
item3->SetPiecewiseFunction(opacityFunction);
item3->SetColor(0.,0.,0.);
item3->SetMaskAboveCurve(true);
chart->AddPlot(item3);
*/
vtkSmartPointer<vtkPiecewiseControlPointsItem> item5 =
vtkSmartPointer<vtkPiecewiseControlPointsItem>::New();
item5->SetPiecewiseFunction(opacityFunction);
......
......@@ -109,14 +109,12 @@ void vtkCompositeTransferFunctionItem::ComputeTexture()
// TBD: maybe the shape should be defined somewhere else...
if (MaskAboveCurve)
{
this->Shape->SetNumberOfPoints(dimension+2);
this->Shape->SetPoint(0, 0.f, 0.f);
this->Shape->SetPoint(dimension + 1, 1.f, 0.f);
this->Shape->SetNumberOfPoints(dimension);
for (int i = 0; i < dimension; ++i)
{
ptr[3] = static_cast<unsigned char>(values[i] * this->Opacity * 255);
assert(values[i] <= 1. && values[i] >= 0.);
this->Shape->SetPoint(i+1,
this->Shape->SetPoint(i,
static_cast<float>(i) * 1.f / (dimension - 1),
values[i] * 1.f);
ptr+=4;
......
......@@ -18,6 +18,7 @@
#include "vtkContext2D.h"
#include "vtkContextScene.h"
#include "vtkControlPointsItem.h"
#include "vtkIdTypeArray.h"
#include "vtkObjectFactory.h"
#include "vtkPen.h"
#include "vtkPoints2D.h"
......@@ -35,11 +36,14 @@ vtkControlPointsItem::vtkControlPointsItem()
this->Brush->SetColorF(0.85, 0.85, 1., 0.75);
this->Points = vtkPoints2D::New();
this->HighlightPoints = vtkPoints2D::New();
this->Selection = vtkIdTypeArray::New();
this->SelectedPoints = vtkPoints2D::New();
this->Callback = vtkCallbackCommand::New();
this->Callback->SetClientData(this);
this->Callback->SetCallback(
vtkControlPointsItem::CallComputePoints);
this->ScreenPointRadius = 6.f;
this->ItemPointRadius2 = 0.f;
}
//-----------------------------------------------------------------------------
......@@ -50,10 +54,10 @@ vtkControlPointsItem::~vtkControlPointsItem()
this->Points->Delete();
this->Points = 0;
}
if (this->HighlightPoints)
if (this->SelectedPoints)
{
this->HighlightPoints->Delete();
this->HighlightPoints = 0;
this->SelectedPoints->Delete();
this->SelectedPoints = 0;
}
if (this->Callback)
{
......@@ -81,15 +85,24 @@ bool vtkControlPointsItem::Paint(vtkContext2D* painter)
{
painter->ApplyPen(this->Pen);
painter->ApplyBrush(this->Brush);
this->DrawPoints(painter, this->Points);
this->DrawPoints(painter, this->Points, this->Selection);
}
if (this->HighlightPoints->GetNumberOfPoints())
if (this->SelectedPoints->GetNumberOfPoints())
{
painter->GetPen()->SetLineType(vtkPen::SOLID_LINE);
painter->GetPen()->SetColorF(0.87, 0.87, 1.);
painter->GetBrush()->SetColorF(0.65, 0.65, 0.95, 0.55);
this->DrawPoints(painter, this->HighlightPoints);
this->DrawPoints(painter, this->SelectedPoints);
}
// control point size in the item coordinate system;
double pointSize[4], transformedPointSize[4];
pointSize[0] = 0.;
pointSize[1] = 0.;
pointSize[2] = 0.;
pointSize[3] = this->ScreenPointRadius;
painter->GetTransform()->InverseTransformPoints(pointSize, transformedPointSize, 2);
this->ItemPointRadius2 = (transformedPointSize[2] - transformedPointSize[0])*(transformedPointSize[2] - transformedPointSize[0]) +
+ (transformedPointSize[3] - transformedPointSize[1])*(transformedPointSize[3] - transformedPointSize[1]);
return true;
}
......@@ -107,53 +120,159 @@ void vtkControlPointsItem::CallComputePoints(
void vtkControlPointsItem::ComputePoints()
{
this->Modified();
if (this->GetScene())
{
this->GetScene()->SetDirty(true);
}
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::DrawPoints(vtkContext2D* painter, vtkPoints2D* points)
void vtkControlPointsItem::DrawPoints(vtkContext2D* painter, vtkPoints2D* points,
vtkIdTypeArray* pointsToExclude)
{
vtkTransform2D* sceneTransform = painter->GetTransform();
vtkSmartPointer<vtkTransform2D> translation =
vtkSmartPointer<vtkTransform2D>::New();
double point[2];
double transformedPoint[2];
double pointInScene[2];
const int count = points->GetNumberOfPoints();
for (int i = 0; i < count; ++i)
const int excludeCount = pointsToExclude ? pointsToExclude->GetNumberOfTuples(): 0;
for (vtkIdType i = 0; i < count; ++i)
{
vtkIdType idx = pointsToExclude ? pointsToExclude->LookupValue(i) : -1;
if (idx != -1)
{
continue;
}
points->GetPoint(i, point);
sceneTransform->TransformPoints(point, transformedPoint, 1);
sceneTransform->TransformPoints(point, pointInScene, 1);
painter->PushMatrix();
translation->Identity();
translation->Translate(transformedPoint[0], transformedPoint[1]);
translation->Translate(pointInScene[0], pointInScene[1]);
painter->SetTransform(translation);
painter->DrawWedge(0.f, 0.f, 6.f, 0.f, 0.f, 360.f);
painter->DrawArc(0.f, 0.f, 6.f, 0.f, 360.f);
painter->DrawWedge(0.f, 0.f, this->ScreenPointRadius, 0.f, 0.f, 360.f);
painter->DrawArc(0.f, 0.f, this->ScreenPointRadius, 0.f, 360.f);
painter->PopMatrix();
}
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::HighlightCurrentPoint(double* currentPoint)
void vtkControlPointsItem::SelectPoint(double* currentPoint)
{
vtkIdType pointId = this->GetPointId(currentPoint);
if (pointId == -1)
{
vtkErrorMacro( << "try to select a point that doesn't exist");
return;
}
this->SelectPoint(pointId);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::SelectPoint(vtkIdType pointId)
{
double point[2];
this->Points->GetPoint(pointId, point);
this->Selection->InsertNextValue(pointId);
this->SelectedPoints->InsertNextPoint(point);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::DeselectPoint(double* currentPoint)
{
// make sure the point belongs to the list of points
vtkIdType pointId = this->GetPointId(currentPoint);
if (pointId == -1)
{
vtkErrorMacro( << "try to deselect a point that doesn't exist");
return;
}
this->DeselectPoint(pointId);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::DeselectPoint(vtkIdType pointId)
{
vtkIdType selectionPointId = this->Selection->LookupValue(pointId);
if (selectionPointId == -1)
{
vtkErrorMacro(<< "Point:" << pointId << " was not selected");
return;
}
this->Selection->RemoveTuple(selectionPointId);
this->SelectedPoints->GetData()->RemoveTuple(selectionPointId);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::DeselectAllPoints()
{
this->Selection->SetNumberOfTuples(0);
this->SelectedPoints->GetData()->SetNumberOfTuples(0);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::ToggleSelectPoint(double* currentPoint)
{
// make sure the point belongs to the list of points
vtkIdType pointId = this->GetPointId(currentPoint);
if (pointId == -1)
{
vtkErrorMacro( << "try to toggle a point that doesn't exist");
return;
}
this->ToggleSelectPoint(pointId);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::ToggleSelectPoint(vtkIdType pointId)
{
vtkIdType selectionId = this->Selection->LookupValue(pointId);
if (selectionId != -1)
{
this->DeselectPoint(pointId);
return;
}
this->SelectPoint(pointId);
}
//-----------------------------------------------------------------------------
vtkIdType vtkControlPointsItem::GetPointId(double* pos, double tolerance)
{
// initialize local variables...
double* point = NULL;
int numberOfPoints = this->HighlightPoints->GetNumberOfPoints();
int i = 0;
// Is the current point highlighted?
// ->invert state
while(i<numberOfPoints)
if (tolerance == -1.)
{
// Add 1.5 ratio for imprecision
tolerance = this->ItemPointRadius2* 1.5;
}
// make sure the point belongs to the list of points
vtkIdType pointId = -1;
double point[2];
double minDist = VTK_DOUBLE_MAX;
const int numberOfPoints = this->Points->GetNumberOfPoints();
for(vtkIdType i = 0; i < numberOfPoints; ++i)
{
point = this->HighlightPoints->GetPoint(i);
if(point[0] == currentPoint[0])
this->Points->GetPoint(i, point);
double distance = (point[0] - pos[0]) * (point[0] - pos[0]) +
(point[1] - pos[1]) * (point[1] - pos[1]);
if (distance < tolerance)
{
if (distance == 0.)
{// we found the best match ever
return i;
}
else if (distance < minDist)
{
pointId = i;
minDist = distance;
}
}
// don't search any further if the x is already too large
if (point[0] > pos[0] + this->ItemPointRadius2)
{
this->HighlightPoints->GetData()->RemoveTuple(i);
return;
break;
}
++i;
}
// If we are here: point not found : add it
this->HighlightPoints->InsertNextPoint(currentPoint);
return pointId;
}
......@@ -31,7 +31,17 @@ public:
virtual void GetBounds(double bounds[4]);
virtual bool Paint(vtkContext2D *painter);
void HighlightCurrentPoint(double* currentPoint);
void SelectPoint(double* currentPoint);
void SelectPoint(vtkIdType pointId);
void DeselectPoint(double* currentPoint);
void DeselectPoint(vtkIdType pointId);
void DeselectAllPoints();
void ToggleSelectPoint(double* currentPoint);
void ToggleSelectPoint(vtkIdType pointId);
// if tolerance is -1, then use the ItemPointSize as a tolerance
vtkIdType GetPointId(double* pos, double tolerance = -1.);
protected:
vtkControlPointsItem();
......@@ -39,12 +49,14 @@ protected:
static void CallComputePoints(vtkObject* sender, unsigned long event, void* receiver, void* params);
virtual void ComputePoints();
void DrawPoints(vtkContext2D* painter, vtkPoints2D* points);
void DrawPoints(vtkContext2D* painter, vtkPoints2D* points, vtkIdTypeArray* excludePoints = 0);
vtkPoints2D* Points;
vtkPoints2D* HighlightPoints;
vtkPoints2D* Points;
vtkPoints2D* SelectedPoints;
vtkCallbackCommand* Callback;
float ScreenPointRadius;
float ItemPointRadius2;
private:
vtkControlPointsItem(const vtkControlPointsItem &); // Not implemented.
void operator=(const vtkControlPointsItem &); // Not implemented.
......
......@@ -16,6 +16,7 @@
#include "vtkBrush.h"
#include "vtkCallbackCommand.h"
#include "vtkContext2D.h"
#include "vtkIdTypeArray.h"
#include "vtkPiecewiseFunction.h"
#include "vtkPiecewiseControlPointsItem.h"
#include "vtkObjectFactory.h"
......@@ -38,7 +39,6 @@ vtkPiecewiseControlPointsItem::vtkPiecewiseControlPointsItem()
this->PiecewiseFunction = 0;
MouseOver = -1;
MouseButtonPressed = -1;
}
//-----------------------------------------------------------------------------
......@@ -76,111 +76,151 @@ void vtkPiecewiseControlPointsItem::SetPiecewiseFunction(vtkPiecewiseFunction* t
}
//-----------------------------------------------------------------------------
// good or not...?
void vtkPiecewiseControlPointsItem::ComputePoints()
{
const int size = this->PiecewiseFunction ? this->PiecewiseFunction->GetSize() : 0;
int size = this->PiecewiseFunction ? this->PiecewiseFunction->GetSize() : 0;
this->Points->SetNumberOfPoints(size);
if (!size)
{
this->Selection->SetNumberOfTuples(0);
this->SelectedPoints->SetNumberOfPoints(0);
return;
}
double node[4];
for (int i = 0; i < size; ++i)
for (vtkIdType i = 0; i < size; ++i)
{
this->PiecewiseFunction->GetNodeValue(i,node);
this->Points->SetPoint(i, node[0], node[1]);
}
}
//-----------------------------------------------------------------------------
bool vtkPiecewiseControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
{
if(this->MouseOver >= 0)
size = this->Selection->GetNumberOfTuples();
if (size)
{
return true;
vtkIdTypeArray* oldSelection = this->Selection;
vtkPoints2D* oldSelectedPoints = this->SelectedPoints;
this->Selection = vtkIdTypeArray::New();
this->SelectedPoints = vtkPoints2D::New();
for (vtkIdType i = 0; i < size; ++i)
{
this->SelectPoint(oldSelection->GetValue(i));
}
oldSelection->Delete();
oldSelectedPoints->Delete();
}
return false;
this->Superclass::ComputePoints();
}
//-----------------------------------------------------------------------------
bool vtkPiecewiseControlPointsItem::MouseEnterEvent(const vtkContextMouseEvent &mouse)
bool vtkPiecewiseControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
{
// Not efficient enough there must be a better way ...
// Get the index of the current point
double x = mouse.Pos[0];
int numberOfNodes = this->PiecewiseFunction->GetSize();
double val[4];
double closeVal = std::numeric_limits<double>::max();
double closeID;
double diff;
for(int i=0; i< numberOfNodes; ++i)
{
this->PiecewiseFunction->GetNodeValue(i, val);
diff = abs(val[0]-x);
if(diff < closeVal)
{
closeVal = diff;
this->MouseOver = i;
}
}
return true;
double pos[2];
pos[0] = mouse.Pos[0];
pos[1] = mouse.Pos[1];
return this->GetPointId(pos) != -1;
}
//-----------------------------------------------------------------------------
bool vtkPiecewiseControlPointsItem::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
if(this->MouseButtonPressed >= 0)
if (mouse.Button != vtkContextMouseEvent::LEFT_BUTTON)
{
double currentPoint[4] = {0.0};
return false;
}
if (this->MouseOver >= 0)
{
double currentPoint[4] = {0.0, 0.0, 0.0, 0.0};
this->PiecewiseFunction->GetNodeValue(this->MouseOver, currentPoint);
this->PiecewiseFunction->RemovePoint(currentPoint[0]);
this->PiecewiseFunction->AddPoint(mouse.Pos[0], mouse.Pos[1]);
// Update this->Highlight
//this->PiecewiseFunction->Update();
//this->Update();
currentPoint[0] = mouse.Pos[0];
currentPoint[1] = mouse.Pos[1];
this->PiecewiseFunction->SetNodeValue(this->MouseOver, currentPoint);
return true;
}
else // should only happen on a draw mode
{
//this->PiecewiseFunction->AddPoint(mouse.Pos[0], mouse.Pos[1]);
}
return false;
}
//-----------------------------------------------------------------------------
bool vtkPiecewiseControlPointsItem::MouseLeaveEvent(const vtkContextMouseEvent &mouse)
{
this->MouseOver = -1;
return true;
}
//-----------------------------------------------------------------------------
bool vtkPiecewiseControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
{
this->LastPosition[0] = mouse.Pos[0];
this->LastPosition[1] = mouse.Pos[1];
this->MouseButtonPressed = mouse.Button;
if (mouse.Button != vtkContextMouseEvent::LEFT_BUTTON)
{
return false;
}
this->ButtonPressPosition[0] = mouse.Pos[0];
this->ButtonPressPosition[1] = mouse.Pos[1];
double pos[2];
pos[0] = mouse.Pos[0];
pos[1] = mouse.Pos[1];
this->MouseOver = this->GetPointId(pos);
if (this->MouseOver == -1)
{
this->DeselectAllPoints();
this->GetScene()->SetDirty(true);
return false;
}
return true;
}
//-----------------------------------------------------------------------------
bool vtkPiecewiseControlPointsItem::MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse)
{
int deltaX = static_cast<int>(mouse.Pos[0] - this->LastPosition[0]);
int deltaY = static_cast<int>(mouse.Pos[1] - this->LastPosition[1]);
if (mouse.Button != vtkContextMouseEvent::LEFT_BUTTON)
{
return false;
}
int deltaX = static_cast<int>(mouse.Pos[0] - this->ButtonPressPosition[0]);
int deltaY = static_cast<int>(mouse.Pos[1] - this->ButtonPressPosition[1]);
double point[2];
point[0] = mouse.Pos[0];
point[1] = mouse.Pos[1];
// If there is a point under the mouse, invert its state (highlight or not)
if((this->MouseOver >= 0) && (deltaX == 0) && (deltaY == 0))
if (this->MouseOver != -1 &&
(deltaX * deltaX + deltaY * deltaY < this->ItemPointRadius2))
{
double currentPoint[4] = {0.0};
// Get the coordinates of the current point
this->PiecewiseFunction->GetNodeValue(this->MouseOver, currentPoint);
HighlightCurrentPoint(currentPoint);
vtkIdType pointId = this->GetPointId(point);
if (pointId != -1)
{
this->ToggleSelectPoint(pointId);
this->GetScene()->SetDirty(true);
this->MouseOver = -1;
return true;
}
}
this->MouseButtonPressed = -1;
return true;
if (this->MouseOver == -1)
{
// offset all the point ids
vtkIdType nextPointId = -1;
int size = this->Points->GetNumberOfPoints();
for (vtkIdType i = 0; i < size; ++i)
{
double* point = this->Points->GetPoint(i);
if (point[0] > mouse.Pos[0])
{
nextPointId = i;
break;
}
}
if (nextPointId != -1)
{
size = this->Selection->GetNumberOfTuples();
for (vtkIdType i = 0; i < size; ++i)
{
vtkIdType pointId = this->Selection->GetValue(i);
if (pointId > nextPointId)
{
this->Selection->SetValue(i, ++pointId);
}
}
}
this->PiecewiseFunction->AddPoint(mouse.Pos[0], mouse.Pos[1]);
// TBD should the point be selected by default ?
//this->DeselectAllPoints();
return true;
}
this->MouseOver = -1;
return false;
}
......@@ -40,18 +40,10 @@ protected:
// Returns true if the supplied x, y coordinate is inside the item.
virtual bool Hit(const vtkContextMouseEvent &mouse);
// Description:
// Mouse enter event.
virtual bool MouseEnterEvent(const vtkContextMouseEvent &mouse);
// Description:
// Mouse move event.
virtual bool MouseMoveEvent(const vtkContextMouseEvent &mouse);
// Description:
// Mouse leave event.
virtual bool MouseLeaveEvent(const vtkContextMouseEvent &mouse);
// Description:
// Mouse button down event.
virtual bool MouseButtonPressEvent(const vtkContextMouseEvent &mouse);
......@@ -62,10 +54,8 @@ protected:
vtkPiecewiseFunction* PiecewiseFunction;
float LastPosition[2];
int MouseOver;
int MouseButtonPressed;
float ButtonPressPosition[2];
vtkIdType MouseOver;
private:
vtkPiecewiseControlPointsItem(const vtkPiecewiseControlPointsItem &); // Not implemented.
......
......@@ -124,15 +124,25 @@ void vtkPiecewiseFunctionItem::ComputeTexture()
reinterpret_cast<unsigned char*>(this->Texture->GetScalarPointer(0,0,0));
if (MaskAboveCurve)
{
this->Shape->SetNumberOfPoints(dimension + 2 );
this->Shape->SetPoint(0, 0.f, 0.f);
this->Shape->SetPoint(dimension + 1, 1.f, 0.f);
/*
this->Shape->SetNumberOfPoints(dimension + 4);
this->Shape->SetPoint(0, 0.f, 0.f);
this->Shape->SetPoint(1, 0.f, values[0]);
this->Shape->SetPoint(dimension + 2, 1.f, values[dimension-1]);
this->Shape->SetPoint(dimension + 3, 1.f, 0.f);
*/
this->Shape->SetNumberOfPoints(dimension);
/*
this->Shape->SetNumberOfPoints(dimension + 2);
this->Shape->SetPoint(0, bounds[0], 0.f);
this->Shape->SetPoint(dimension + 1, bounds[1], 0.f);
*/
for (int i = 0; i < dimension; ++i)
{
this->Pen->GetColor(ptr);
ptr[3] = static_cast<unsigned char>(values[i] * this->Opacity * 255 + 0.5);
assert(values[i] <= 1. && values[i] >= 0.);
this->Shape->SetPoint(i + 1, static_cast<float>(i) * 1.f / (dimension-1),
this->Shape->SetPoint(i, static_cast<float>(i) * 1.f / (dimension-1),
values[i] * 1.f);
ptr+=4;
}
......
......@@ -91,14 +91,32 @@ bool vtkScalarsToColorsItem::Paint(vtkContext2D* painter)
this->ComputeTexture();
}
painter->ApplyPen(this->Pen);
painter->GetBrush()->SetColorF(0., 0.,0.,1.);
painter->GetBrush()->SetColorF(1., 1., 1., 1.);
painter->GetBrush()->SetTexture(this->Texture);
painter->GetBrush()->SetTextureProperties(
(this->Interpolate ? vtkBrush::Nearest : vtkBrush::Linear) |
vtkBrush::Stretch);
painter->DrawPolygon(this->Shape);
const int size = this->Shape->GetNumberOfPoints();
if (size == 4)
{
painter->DrawPolygon(this->Shape);
}
else
{
vtkPoints2D* trapezoids = vtkPoints2D::New();
trapezoids->SetNumberOfPoints(2*size);
double point[2];
vtkIdType j = -1;
for (vtkIdType i = 0; i < size; ++i)
{
this->Shape->GetPoint(i, point);
trapezoids->SetPoint(++j, point[0], 0.);
trapezoids->SetPoint(++j, point);
}
painter->DrawQuadStrip(trapezoids);
trapezoids->Delete();
}
return true;
}
......
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