Commit fea2d622 authored by Julien Finet's avatar Julien Finet Committed by Kitware Robot
Browse files

Merge topic 'charts-lock-to-bounds'

96577556 Emit interaction events when moving control points
44fdb1a4 Add vtkControlPointsItem::MovePoints utility functions
cbb34abb vtkControlPointsItem supports larger bounds for point moves
83c858d0 It is not necessarily an error to have opacity ouside [0,1]
2ae2e104 Add vtkControlPointsItem::BlockUpdates
parents e0571ebd 96577556
......@@ -6,6 +6,7 @@ IF(VTK_USE_RENDERING AND VTK_USE_VIEWS)
SET(MyTests
TestContextScene.cxx
TestControlPointsItem.cxx
TestControlPointsItemEvents.cxx
TestVector.cxx
)
......
/*=========================================================================
Program: Visualization Toolkit
Module: TestVector.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.
=========================================================================*/
// Charts includes
#include "vtkContextInteractorStyle.h"
#include "vtkContextScene.h"
#include "vtkControlPointsItem.h"
#include "vtkColorTransferControlPointsItem.h"
#include "vtkColorTransferFunction.h"
// Common includes"
#include "vtkIdTypeArray.h"
#include "vtkInteractorEventRecorder.h"
#include "vtkNew.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkSmartPointer.h"
// STD includes
#include <iostream>
#include <map>
//----------------------------------------------------------------------------
class vtkTFCallback : public vtkCommand
{
public:
static vtkTFCallback *New()
{
return new vtkTFCallback;
}
vtkTFCallback()
{
}
void Execute( vtkObject *caller, unsigned long event,
void *vtkNotUsed(callData) )
{
vtkColorTransferFunction* self =
reinterpret_cast< vtkColorTransferFunction* >( caller );
if (!self)
{
return;
}
if (this->EventSpy.count(event) == 0)
{
this->EventSpy[event] = 0;
}
++this->EventSpy[event];
std::cout << "InvokedEvent: " << event << this->EventSpy[event] << std::endl;
}
std::map<unsigned long, int> EventSpy;
};
//----------------------------------------------------------------------------
int TestControlPointsItemEvents(int, char*[])
{
vtkNew<vtkColorTransferFunction> transferFunction;
transferFunction->AddHSVSegment(50.,0.,1.,1.,85.,0.3333,1.,1.);
transferFunction->AddHSVSegment(85.,0.3333,1.,1.,170.,0.6666,1.,1.);
transferFunction->AddHSVSegment(170.,0.6666,1.,1.,200.,0.,1.,1.);
vtkNew<vtkTFCallback> cbk;
transferFunction->AddObserver( vtkCommand::StartEvent, cbk.GetPointer() );
transferFunction->AddObserver( vtkCommand::ModifiedEvent, cbk.GetPointer() );
transferFunction->AddObserver( vtkCommand::EndEvent, cbk.GetPointer() );
transferFunction->AddObserver( vtkCommand::StartInteractionEvent, cbk.GetPointer() );
transferFunction->AddObserver( vtkCommand::InteractionEvent, cbk.GetPointer() );
transferFunction->AddObserver( vtkCommand::EndInteractionEvent, cbk.GetPointer() );
vtkNew<vtkColorTransferControlPointsItem> controlPoints;
controlPoints->SetColorTransferFunction(transferFunction.GetPointer());
// vtkNew<vtkChartXY> chart;
// chart->AddPlot(controlPoints.GetPointer());
vtkNew<vtkContextScene> scene;
scene->AddItem(controlPoints.GetPointer());
vtkNew<vtkContextInteractorStyle> interactorStyle;
interactorStyle->SetScene(scene.GetPointer());
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetInteractorStyle(interactorStyle.GetPointer());
vtkNew<vtkInteractorEventRecorder> recorder;
recorder->SetInteractor(iren.GetPointer());
recorder->ReadFromInputStringOn();
// Add a point at (60, 0.5) and move it to (62, 0.5)
const char addAndDragEvents[] =
"# StreamVersion 1\n"
"LeftButtonPressEvent 60 1 0 0 0 0 0\n"
"MouseMoveEvent 62 1 0 0 0 0 0\n"
"LeftButtonReleaseEvent 62 1 0 0 0 0 0\n"
;
recorder->SetInputString(addAndDragEvents);
recorder->Play();
// 1 ModifiedEvent for adding a point
// 1 ModifiedEvent for moving the point
if (cbk->EventSpy[vtkCommand::ModifiedEvent] != 2 ||
cbk->EventSpy[vtkCommand::StartInteractionEvent] != 1 ||
cbk->EventSpy[vtkCommand::InteractionEvent] != 1 ||
cbk->EventSpy[vtkCommand::EndInteractionEvent] != 1 ||
cbk->EventSpy[vtkCommand::StartEvent] != 0 ||
cbk->EventSpy[vtkCommand::EndEvent] != 0)
{
std::cerr << "Wrong number of fired events : "
<< cbk->EventSpy[vtkCommand::ModifiedEvent] << " "
<< cbk->EventSpy[vtkCommand::StartInteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::InteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::EndInteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::StartEvent] << " "
<< cbk->EventSpy[vtkCommand::EndEvent] << std::endl;
return EXIT_FAILURE;
}
cbk->EventSpy.clear();
// Move all the points to the right.
controlPoints->MovePoints(vtkVector2f(5, 0.));
// One ModifiedEvent for each moved point
if (cbk->EventSpy[vtkCommand::ModifiedEvent] > controlPoints->GetNumberOfPoints() ||
cbk->EventSpy[vtkCommand::StartInteractionEvent] != 0 ||
cbk->EventSpy[vtkCommand::InteractionEvent] != 0 ||
cbk->EventSpy[vtkCommand::EndInteractionEvent] != 0 ||
cbk->EventSpy[vtkCommand::StartEvent] != 1 ||
cbk->EventSpy[vtkCommand::EndEvent] != 1)
{
std::cerr << "Wrong number of fired events : "
<< cbk->EventSpy[vtkCommand::ModifiedEvent] << " "
<< cbk->EventSpy[vtkCommand::StartInteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::InteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::EndInteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::StartEvent] << " "
<< cbk->EventSpy[vtkCommand::EndEvent] << std::endl;
return EXIT_FAILURE;
}
cbk->EventSpy.clear();
const char dblClickEvents[] =
"# StreamVersion 1\n"
"MouseMoveEvent 56 1 0 0 0 0 0\n" // shouldn't move the point
"LeftButtonPressEvent 55 1 0 0 0 0 0\n" // select the first point
"LeftButtonReleaseEvent 55 1 0 0 0 0 0\n"
"LeftButtonPressEvent 55 1 0 0 0 1 0\n" // dbl click
"MouseMoveEvent 56 1 0 0 0 0 0\n" // shouldn't move the point
;
recorder->SetInputString(dblClickEvents);
recorder->Play();
if (cbk->EventSpy[vtkCommand::ModifiedEvent] != 0 ||
cbk->EventSpy[vtkCommand::StartInteractionEvent] != 0 ||
cbk->EventSpy[vtkCommand::InteractionEvent] != 0 ||
cbk->EventSpy[vtkCommand::EndInteractionEvent] != 0 ||
cbk->EventSpy[vtkCommand::StartEvent] != 0 ||
cbk->EventSpy[vtkCommand::EndEvent] != 0)
{
std::cerr << "Wrong number of fired events : "
<< cbk->EventSpy[vtkCommand::ModifiedEvent] << " "
<< cbk->EventSpy[vtkCommand::StartInteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::InteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::EndInteractionEvent] << " "
<< cbk->EventSpy[vtkCommand::StartEvent] << " "
<< cbk->EventSpy[vtkCommand::EndEvent] << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
......@@ -67,6 +67,15 @@ void vtkColorTransferControlPointsItem::PrintSelf(ostream &os, vtkIndent indent)
}
}
//-----------------------------------------------------------------------------
void vtkColorTransferControlPointsItem::emitEvent(unsigned long event, void* params)
{
if (this->ColorTransferFunction)
{
this->ColorTransferFunction->InvokeEvent(event, params);
}
}
//-----------------------------------------------------------------------------
unsigned long int vtkColorTransferControlPointsItem::GetControlPointsMTime()
{
......@@ -80,6 +89,10 @@ unsigned long int vtkColorTransferControlPointsItem::GetControlPointsMTime()
//-----------------------------------------------------------------------------
void vtkColorTransferControlPointsItem::SetColorTransferFunction(vtkColorTransferFunction* t)
{
if (t == this->ColorTransferFunction)
{
return;
}
if (this->ColorTransferFunction)
{
this->ColorTransferFunction->RemoveObserver(this->Callback);
......@@ -87,7 +100,9 @@ void vtkColorTransferControlPointsItem::SetColorTransferFunction(vtkColorTransfe
vtkSetObjectBodyMacro(ColorTransferFunction, vtkColorTransferFunction, t);
if (this->ColorTransferFunction)
{
this->ColorTransferFunction->AddObserver(vtkCommand::StartEvent, this->Callback);
this->ColorTransferFunction->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
this->ColorTransferFunction->AddObserver(vtkCommand::EndEvent, this->Callback);
}
this->ResetBounds();
this->ComputePoints();
......
......@@ -85,6 +85,8 @@ protected:
vtkColorTransferControlPointsItem();
virtual ~vtkColorTransferControlPointsItem();
virtual void emitEvent(unsigned long event, void* params);
virtual unsigned long int GetControlPointsMTime();
virtual void DrawPoint(vtkContext2D* painter, vtkIdType index);
......
......@@ -40,7 +40,6 @@ vtkCompositeControlPointsItem::vtkCompositeControlPointsItem()
{
this->PointsFunction = ColorAndOpacityPointsFunction;
this->OpacityFunction = 0;
this->Updating = false;
this->ColorFill = true;
}
......@@ -70,6 +69,16 @@ void vtkCompositeControlPointsItem::PrintSelf(ostream &os, vtkIndent indent)
}
}
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::emitEvent(unsigned long event, void* params)
{
if (this->OpacityFunction)
{
this->OpacityFunction->InvokeEvent(event, params);
}
this->Superclass::emitEvent(event, params);
}
//-----------------------------------------------------------------------------
unsigned long int vtkCompositeControlPointsItem::GetControlPointsMTime()
{
......@@ -84,6 +93,10 @@ unsigned long int vtkCompositeControlPointsItem::GetControlPointsMTime()
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetOpacityFunction(vtkPiecewiseFunction* function)
{
if (function == this->OpacityFunction)
{
return;
}
if (this->OpacityFunction)
{
this->OpacityFunction->RemoveObserver(this->Callback);
......@@ -95,7 +108,9 @@ void vtkCompositeControlPointsItem::SetOpacityFunction(vtkPiecewiseFunction* fun
}
if (this->OpacityFunction)
{
this->OpacityFunction->AddObserver(vtkCommand::StartEvent, this->Callback);
this->OpacityFunction->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
this->OpacityFunction->AddObserver(vtkCommand::EndEvent, this->Callback);
}
this->ResetBounds();
this->ComputePoints();
......@@ -104,6 +119,10 @@ void vtkCompositeControlPointsItem::SetOpacityFunction(vtkPiecewiseFunction* fun
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetColorTransferFunction(vtkColorTransferFunction* c)
{
if (c == this->ColorTransferFunction)
{
return;
}
// Observation will be set Superclass::SetColorTransferFunction
if (this->ColorTransferFunction)
{
......@@ -119,15 +138,6 @@ void vtkCompositeControlPointsItem::SetColorTransferFunction(vtkColorTransferFun
}
this->Superclass::SetColorTransferFunction(c);
}
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::ComputePoints()
{
if (this->Updating)
{
return;
}
this->Superclass::ComputePoints();
}
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::DrawPoint(vtkContext2D* painter, vtkIdType index)
......@@ -234,28 +244,23 @@ void vtkCompositeControlPointsItem::EditPoint(float tX, float tY)
vtkIdType vtkCompositeControlPointsItem::AddPoint(double* newPos)
{
vtkIdType addedPoint = -1;
this->StartChanges();
if (this->OpacityFunction &&
(this->PointsFunction == OpacityPointsFunction ||
this->PointsFunction == ColorAndOpacityPointsFunction))
{
bool oldUpdating = this->Updating;
if (this->PointsFunction == ColorAndOpacityPointsFunction)
{
this->Updating = true;
}
addedPoint = this->OpacityFunction->AddPoint(newPos[0], newPos[1]);
if (this->PointsFunction == OpacityPointsFunction)
{
this->vtkControlPointsItem::AddPointId(addedPoint);
}
this->Updating = oldUpdating;
}
if (this->PointsFunction == ColorPointsFunction ||
this->PointsFunction == ColorAndOpacityPointsFunction)
{
addedPoint = this->Superclass::AddPoint(newPos);
}
this->EndChanges();
return addedPoint;
}
......@@ -263,16 +268,11 @@ vtkIdType vtkCompositeControlPointsItem::AddPoint(double* newPos)
vtkIdType vtkCompositeControlPointsItem::RemovePoint(double* currentPoint)
{
vtkIdType removedPoint = -1;
this->StartChanges();
if (this->PointsFunction == ColorPointsFunction ||
this->PointsFunction == ColorAndOpacityPointsFunction)
{
bool oldUpdating = this->Updating;
if (this->PointsFunction == ColorAndOpacityPointsFunction)
{
this->Updating = true;
}
removedPoint = this->Superclass::RemovePoint(currentPoint);
this->Updating = oldUpdating;
}
if (this->OpacityFunction &&
(this->PointsFunction == OpacityPointsFunction ||
......@@ -280,6 +280,7 @@ vtkIdType vtkCompositeControlPointsItem::RemovePoint(double* currentPoint)
{
removedPoint = this->OpacityFunction->RemovePoint(currentPoint[0]);
}
this->EndChanges();
return removedPoint;
}
......@@ -318,7 +319,7 @@ void vtkCompositeControlPointsItem::MergeTransferFunctions()
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SilentMergeTransferFunctions()
{
bool wasUpdating = this->Updating;
this->StartChanges();
this->MergeTransferFunctions();
this->Updating = wasUpdating;
this->EndChanges();
}
......@@ -50,7 +50,7 @@ public:
void SetOpacityFunction(vtkPiecewiseFunction* opacity);
vtkGetObjectMacro(OpacityFunction, vtkPiecewiseFunction);
enum PointsFunction{
enum PointsFunctionType{
ColorPointsFunction = 1,
OpacityPointsFunction = 2,
ColorAndOpacityPointsFunction = 3
......@@ -85,8 +85,9 @@ protected:
vtkCompositeControlPointsItem();
virtual ~vtkCompositeControlPointsItem();
virtual void emitEvent(unsigned long event, void* params);
virtual unsigned long int GetControlPointsMTime();
virtual void ComputePoints();
virtual vtkIdType GetNumberOfPoints()const;
virtual void DrawPoint(vtkContext2D* painter, vtkIdType index);
......@@ -99,7 +100,6 @@ protected:
int PointsFunction;
vtkPiecewiseFunction* OpacityFunction;
bool Updating;
private:
vtkCompositeControlPointsItem(const vtkCompositeControlPointsItem &); // Not implemented.
......
......@@ -116,7 +116,11 @@ void vtkCompositeTransferFunctionItem::ComputeTexture()
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.);
if (values[i] < 0. || values[i] > 1.)
{
vtkWarningMacro( << "Opacity at point " << i << " is " << values[i]
<< " wich is outside the valid range of [0,1]");
}
this->Shape->SetPoint(i, bounds[0] + step * i, values[i]);
ptr+=4;
}
......
......@@ -51,6 +51,9 @@ vtkControlPointsItem::vtkControlPointsItem()
this->Selection = vtkIdTypeArray::New();
this->CurrentPoint = -1;
this->BlockUpdates = 0;
this->StartedInteractions = 0;
this->Callback = vtkCallbackCommand::New();
this->Callback->SetClientData(this);
this->Callback->SetCallback(
......@@ -60,6 +63,8 @@ vtkControlPointsItem::vtkControlPointsItem()
this->Bounds[1] = this->Bounds[3] = -1.;
this->UserBounds[0] = this->UserBounds[2] = 0.;
this->UserBounds[1] = this->UserBounds[3] = -1.;
this->ValidBounds[0] = this->ValidBounds[2] = 0.;
this->ValidBounds[1] = this->ValidBounds[3] = -1.;
this->ScreenPointRadius = 6.f;
this->Transform = vtkTransform2D::New();
......@@ -206,19 +211,93 @@ bool vtkControlPointsItem::Paint(vtkContext2D* painter)
return true;
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::StartChanges()
{
this->emitEvent(vtkCommand::StartEvent);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::EndChanges()
{
this->emitEvent(vtkCommand::EndEvent);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::StartInteraction()
{
++this->StartedInteractions;
this->emitEvent(vtkCommand::StartInteractionEvent);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::StartInteractionIfNotStarted()
{
if (this->GetInteractionsCount() == 0)
{
this->StartInteraction();
}
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::Interaction()
{
assert(this->StartedInteractions > 0);
this->emitEvent(vtkCommand::InteractionEvent);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::EndInteraction()
{
--this->StartedInteractions;
assert(this->StartedInteractions >= 0);
this->emitEvent(vtkCommand::EndInteractionEvent);
}
//-----------------------------------------------------------------------------
int vtkControlPointsItem::GetInteractionsCount()const
{
return this->StartedInteractions;
}
//-----------------------------------------------------------------------------
//void vtkControlPointsItem::emitEvent(unsigned long event, void* params);
//-----------------------------------------------------------------------------
void vtkControlPointsItem::CallComputePoints(
vtkObject* vtkNotUsed(sender), unsigned long vtkNotUsed(event),
vtkObject* vtkNotUsed(sender), unsigned long event,
void* receiver, void* vtkNotUsed(params))
{
vtkControlPointsItem* item =
reinterpret_cast<vtkControlPointsItem*>(receiver);
item->ComputePoints();
switch(event)
{
case vtkCommand::StartEvent:
++item->BlockUpdates;
break;
case vtkCommand::EndEvent:
--item->BlockUpdates;
if (item->BlockUpdates == 0)
{
item->ComputePoints();
}
break;
case vtkCommand::ModifiedEvent:
item->ComputePoints();
break;
default:
break;
}
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::ComputePoints()
{
if (this->BlockUpdates > 0)
{
return;
}
if (this->GetNumberOfPoints() == 0)
{
this->Selection->SetNumberOfTuples(0);
......@@ -250,7 +329,9 @@ bool vtkControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
double pos[2];
pos[0] = mouse.Pos[0];
pos[1] = mouse.Pos[1];
bool clamped = this->ClampPos(pos);
double bounds[4];
this->GetBounds(bounds);
bool clamped = this->ClampPos(pos, bounds);
if (!clamped)
{
return true;
......@@ -270,10 +351,8 @@ bool vtkControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::ClampPos(double pos[2])
bool vtkControlPointsItem::ClampPos(double pos[2], double bounds[4])
{
double bounds[4];
this->GetBounds(bounds);
bool clamped = false;
if (pos[0] < bounds[0])
{
......@@ -298,6 +377,21 @@ bool vtkControlPointsItem::ClampPos(double pos[2])
return clamped;
}
//-----------------------------------------------------------------------------
bool vtkControlPointsItem::ClampValidPos(double pos[2])
{
double validBounds[4];
this->GetValidBounds(validBounds);
if (validBounds[0] > this->ValidBounds[1] ||
validBounds[2] > this->ValidBounds[3])
{
double bounds[4];
this->GetBounds(bounds);
return this->ClampPos(pos, bounds);
}
return this->ClampPos(pos, validBounds);
}
//-----------------------------------------------------------------------------
void vtkControlPointsItem::DrawUnselectedPoints(vtkContext2D* painter)
{
......@@ -767,7 +861,7 @@ bool vtkControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mou
&& this->Selection->GetNumberOfTuples() <= 1
&& !this->StrokeMode)
{
this->ClampPos(pos);
this->ClampPos(pos, this->GetValidBounds());
vtkIdType addedPoint = this->AddPoint(pos);
this->SetCurrentPoint(addedPoint);
return true;
......@@ -832,20 +926,32 @@ bool vtkControlPointsItem::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
if (this->StrokeMode)
{
this->StartInteractionIfNotStarted();
this->Stroke(mouse.Pos);
this->Interaction();
}
else if (this->CurrentPoint == -1 && this->Selection->GetNumberOfTuples() > 1)
{
this->StartInteractionIfNotStarted();
vtkIdTypeArray* points = this->GetSelection();
points->Register(this);// must stay valid after each individual point move
this->MovePoints(
vtkVector2f(mouse.Pos[0] - mouse.LastPos[0], mouse.Pos[1] - mouse.LastPos[1]),
points);
points->UnRegister(this);