Commit 735a85e5 authored by Ken Martin's avatar Ken Martin

update widget representations to handle 3D events

The old event signatures were limited to X Y mouse
events and not flexible enough for general event handling.
These updated signatures allow for much more flexibility.

This topic also switches the distance withget to use a
double representation for the glyph to avoid float
resolution issues with large coordinate systems.

This topic adds handling for 3D events to the point handle
and distance representations and widgets.
parent 897333f9
......@@ -15,12 +15,14 @@
#include "vtkDistanceRepresentation.h"
#include "vtkHandleRepresentation.h"
#include "vtkCoordinate.h"
#include "vtkEventData.h"
#include "vtkRenderer.h"
#include "vtkObjectFactory.h"
#include "vtkBox.h"
#include "vtkInteractorObserver.h"
#include "vtkMath.h"
#include "vtkWindow.h"
#include "vtkRenderWindowInteractor.h"
vtkCxxSetObjectMacro(vtkDistanceRepresentation,HandleRepresentation,vtkHandleRepresentation);
......@@ -122,6 +124,35 @@ ComputeInteractionState(int vtkNotUsed(X), int vtkNotUsed(Y), int vtkNotUsed(mod
return this->InteractionState;
}
int vtkDistanceRepresentation::ComputeComplexInteractionState(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long , void *, int )
{
if (this->Point1Representation == nullptr || this->Point2Representation == nullptr)
{
this->InteractionState = vtkDistanceRepresentation::Outside;
return this->InteractionState;
}
int h1State = this->Point1Representation->GetInteractionState();
int h2State = this->Point2Representation->GetInteractionState();
if ( h1State == vtkHandleRepresentation::Nearby )
{
this->InteractionState = vtkDistanceRepresentation::NearP1;
}
else if ( h2State == vtkHandleRepresentation::Nearby )
{
this->InteractionState = vtkDistanceRepresentation::NearP2;
}
else
{
this->InteractionState = vtkDistanceRepresentation::Outside;
}
return this->InteractionState;
}
//----------------------------------------------------------------------
void vtkDistanceRepresentation::StartWidgetInteraction(double e[2])
{
......@@ -133,6 +164,22 @@ void vtkDistanceRepresentation::StartWidgetInteraction(double e[2])
this->SetPoint2DisplayPosition(pos);
}
void vtkDistanceRepresentation::StartComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long , void *calldata)
{
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
double pos[3];
edd->GetWorldPosition(pos);
this->SetPoint1WorldPosition(pos);
this->SetPoint2WorldPosition(pos);
}
}
//----------------------------------------------------------------------
void vtkDistanceRepresentation::WidgetInteraction(double e[2])
{
......@@ -142,6 +189,20 @@ void vtkDistanceRepresentation::WidgetInteraction(double e[2])
pos[2] = 0.0;
this->SetPoint2DisplayPosition(pos);
}
void vtkDistanceRepresentation::ComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long, void *calldata )
{
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
double pos[3];
edd->GetWorldPosition(pos);
this->SetPoint2WorldPosition(pos);
}
}
//----------------------------------------------------------------------
void vtkDistanceRepresentation::BuildRepresentation()
......
......@@ -169,6 +169,18 @@ public:
int ComputeInteractionState(int X, int Y, int modify=0) VTK_OVERRIDE;
void StartWidgetInteraction(double e[2]) VTK_OVERRIDE;
void WidgetInteraction(double e[2]) VTK_OVERRIDE;
void StartComplexInteraction(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata) VTK_OVERRIDE;
void ComplexInteraction(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata) VTK_OVERRIDE;
int ComputeComplexInteractionState(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata, int modify = 0) VTK_OVERRIDE;
//@}
protected:
......
......@@ -89,6 +89,7 @@ vtkDistanceRepresentation3D::vtkDistanceRepresentation3D()
this->GlyphXForm->SetTransform(xform);
xform->RotateZ(90);
this->Glyph3D = vtkGlyph3D::New();
this->Glyph3D->SetOutputPointsPrecision(vtkAlgorithm::DOUBLE_PRECISION);
this->Glyph3D->SetInputData(this->GlyphPolyData);
this->Glyph3D->SetSourceConnection(this->GlyphXForm->GetOutputPort());
this->Glyph3D->SetScaleModeToDataScalingOff();
......@@ -136,6 +137,31 @@ vtkDistanceRepresentation3D::~vtkDistanceRepresentation3D()
this->BoundingBox->Delete();
}
//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::SetLabelActor(vtkFollower *fol)
{
if (fol == this->LabelActor)
{
return;
}
if (fol)
{
fol->Register(this);
fol->SetMapper(this->LabelMapper);
}
if (this->LabelActor)
{
this->LabelActor->ReleaseGraphicsResources(nullptr);
this->LabelActor->UnRegister(this);
this->LabelActor = nullptr;
}
this->LabelActor = fol;
this->Modified();
}
//----------------------------------------------------------------------
void vtkDistanceRepresentation3D::GetPoint1WorldPosition(double pos[3])
{
......@@ -262,7 +288,8 @@ void vtkDistanceRepresentation3D::BuildRepresentation()
// Label
char string[512];
snprintf(string, sizeof(string), this->LabelFormat, this->Distance);
snprintf(string, sizeof(string), this->LabelFormat, this->Distance,
fabs(p1[0] - p2[0]), fabs(p1[1] - p2[1]), fabs(p1[2] - p2[2]));
this->LabelText->SetText(string);
this->UpdateLabelPosition();
if (this->Renderer) //make the label face the camera
......
......@@ -113,6 +113,7 @@ public:
* control the appearance of the label.
*/
vtkGetObjectMacro(LabelActor, vtkFollower);
virtual void SetLabelActor(vtkFollower *);
//@}
//@{
......
......@@ -20,7 +20,9 @@
#include "vtkRenderer.h"
#include "vtkHandleWidget.h"
#include "vtkCoordinate.h"
#include "vtkEventData.h"
#include "vtkHandleRepresentation.h"
#include "vtkNew.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkWidgetEvent.h"
#include "vtkWidgetEventTranslator.h"
......@@ -103,6 +105,35 @@ vtkDistanceWidget::vtkDistanceWidget()
this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent,
vtkWidgetEvent::EndSelect,
this, vtkDistanceWidget::EndSelectAction);
{
vtkNew<vtkEventDataButton3D> ed;
ed->SetDevice(vtkEventDataDevice::RightController);
ed->SetInput(vtkEventDataDeviceInput::Trigger);
ed->SetAction(vtkEventDataAction::Press);
this->CallbackMapper->SetCallbackMethod(vtkCommand::Button3DEvent,
ed.Get(), vtkWidgetEvent::AddPoint3D,
this, vtkDistanceWidget::AddPointAction3D);
}
{
vtkNew<vtkEventDataButton3D> ed;
ed->SetDevice(vtkEventDataDevice::RightController);
ed->SetInput(vtkEventDataDeviceInput::Trigger);
ed->SetAction(vtkEventDataAction::Release);
this->CallbackMapper->SetCallbackMethod(vtkCommand::Button3DEvent,
ed.Get(), vtkWidgetEvent::EndSelect3D,
this, vtkDistanceWidget::EndSelectAction3D);
}
{
vtkNew<vtkEventDataMove3D> ed;
ed->SetDevice(vtkEventDataDevice::RightController);
this->CallbackMapper->SetCallbackMethod(vtkCommand::Move3DEvent,
ed.Get(), vtkWidgetEvent::Move3D,
this, vtkDistanceWidget::MoveAction3D);
}
}
//----------------------------------------------------------------------
......@@ -311,6 +342,7 @@ void vtkDistanceWidget::AddPointAction(vtkAbstractWidget *w)
else //if ( self->WidgetState == vtkDistanceWidget::Manipulate )
{
int state = self->WidgetRep->ComputeInteractionState(X,Y);
if ( state == vtkDistanceRepresentation::Outside )
{
self->CurrentHandle = -1;
......@@ -326,7 +358,67 @@ void vtkDistanceWidget::AddPointAction(vtkAbstractWidget *w)
{
self->CurrentHandle = 1;
}
self->InvokeEvent(vtkCommand::LeftButtonPressEvent,nullptr);
self->InvokeEvent(vtkCommand::LeftButtonPressEvent, nullptr);
}
// Clean up
self->EventCallbackCommand->SetAbortFlag(1);
self->Render();
}
//-------------------------------------------------------------------------
void vtkDistanceWidget::AddPointAction3D(vtkAbstractWidget *w)
{
vtkDistanceWidget *self = reinterpret_cast<vtkDistanceWidget*>(w);
// Freshly enabled and placing the first point
if ( self->WidgetState == vtkDistanceWidget::Start )
{
self->GrabFocus(self->EventCallbackCommand);
self->WidgetState = vtkDistanceWidget::Define;
self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
reinterpret_cast<vtkDistanceRepresentation*>(self->WidgetRep)->VisibilityOn();
self->WidgetRep->StartComplexInteraction(
self->Interactor, self, vtkWidgetEvent::AddPoint, self->CallData);
self->CurrentHandle = 0;
self->InvokeEvent(vtkCommand::PlacePointEvent,&(self->CurrentHandle));
}
// Placing the second point is easy
else if ( self->WidgetState == vtkDistanceWidget::Define )
{
self->CurrentHandle = 1;
self->InvokeEvent(vtkCommand::PlacePointEvent,&(self->CurrentHandle));
self->WidgetState = vtkDistanceWidget::Manipulate;
self->Point1Widget->SetEnabled(1);
self->Point2Widget->SetEnabled(1);
self->CurrentHandle = -1;
self->ReleaseFocus();
self->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
}
// Maybe we are trying to manipulate the widget handles
else //if ( self->WidgetState == vtkDistanceWidget::Manipulate )
{
int state = self->WidgetRep->ComputeComplexInteractionState(
self->Interactor, self, vtkWidgetEvent::AddPoint, self->CallData);
if ( state == vtkDistanceRepresentation::Outside )
{
self->CurrentHandle = -1;
return;
}
self->GrabFocus(self->EventCallbackCommand);
if ( state == vtkDistanceRepresentation::NearP1 )
{
self->CurrentHandle = 0;
}
else if ( state == vtkDistanceRepresentation::NearP2 )
{
self->CurrentHandle = 1;
}
self->InvokeEvent(vtkCommand::Button3DEvent, self->CallData);
}
// Clean up
......@@ -366,6 +458,34 @@ void vtkDistanceWidget::MoveAction(vtkAbstractWidget *w)
self->Render();
}
//-------------------------------------------------------------------------
void vtkDistanceWidget::MoveAction3D(vtkAbstractWidget *w)
{
vtkDistanceWidget *self = reinterpret_cast<vtkDistanceWidget*>(w);
// Do nothing if in start mode or valid handle not selected
if ( self->WidgetState == vtkDistanceWidget::Start )
{
return;
}
// Delegate the event consistent with the state
if ( self->WidgetState == vtkDistanceWidget::Define )
{
self->WidgetRep->ComplexInteraction(
self->Interactor, self, vtkWidgetEvent::Move3D, self->CallData);
self->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
self->EventCallbackCommand->SetAbortFlag(1);
}
else //must be moving a handle, invoke a event for the handle widgets
{
self->InvokeEvent(vtkCommand::Move3DEvent, self->CallData);
}
self->WidgetRep->BuildRepresentation();
self->Render();
}
//-------------------------------------------------------------------------
void vtkDistanceWidget::EndSelectAction(vtkAbstractWidget *w)
{
......@@ -387,6 +507,27 @@ void vtkDistanceWidget::EndSelectAction(vtkAbstractWidget *w)
self->Render();
}
//-------------------------------------------------------------------------
void vtkDistanceWidget::EndSelectAction3D(vtkAbstractWidget *w)
{
vtkDistanceWidget *self = reinterpret_cast<vtkDistanceWidget*>(w);
// Do nothing if outside
if ( self->WidgetState == vtkDistanceWidget::Start ||
self->WidgetState == vtkDistanceWidget::Define ||
self->CurrentHandle < 0 )
{
return;
}
self->ReleaseFocus();
self->InvokeEvent(vtkCommand::Button3DEvent, self->CallData);
self->CurrentHandle = -1;
self->WidgetRep->BuildRepresentation();
self->EventCallbackCommand->SetAbortFlag(1);
self->Render();
}
// These are callbacks that are active when the user is manipulating the
// handles of the measure widget.
//----------------------------------------------------------------------
......
......@@ -169,6 +169,9 @@ protected:
static void AddPointAction(vtkAbstractWidget*);
static void MoveAction(vtkAbstractWidget*);
static void EndSelectAction(vtkAbstractWidget*);
static void AddPointAction3D(vtkAbstractWidget*);
static void MoveAction3D(vtkAbstractWidget*);
static void EndSelectAction3D(vtkAbstractWidget*);
// The positioning handle widgets
vtkHandleWidget *Point1Widget;
......
......@@ -23,6 +23,7 @@
#include "vtkWidgetEventTranslator.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkEvent.h"
#include "vtkEventData.h"
#include "vtkWidgetEvent.h"
......@@ -56,6 +57,35 @@ vtkHandleWidget::vtkHandleWidget()
this->CallbackMapper->SetCallbackMethod(vtkCommand::MouseMoveEvent,
vtkWidgetEvent::Move,
this, vtkHandleWidget::MoveAction);
{
vtkNew<vtkEventDataButton3D> ed;
ed->SetDevice(vtkEventDataDevice::RightController);
ed->SetInput(vtkEventDataDeviceInput::Trigger);
ed->SetAction(vtkEventDataAction::Press);
this->CallbackMapper->SetCallbackMethod(vtkCommand::Button3DEvent,
ed.Get(), vtkWidgetEvent::Select3D,
this, vtkHandleWidget::SelectAction3D);
}
{
vtkNew<vtkEventDataButton3D> ed;
ed->SetDevice(vtkEventDataDevice::RightController);
ed->SetInput(vtkEventDataDeviceInput::Trigger);
ed->SetAction(vtkEventDataAction::Release);
this->CallbackMapper->SetCallbackMethod(vtkCommand::Button3DEvent,
ed.Get(), vtkWidgetEvent::EndSelect3D,
this, vtkHandleWidget::EndSelectAction);
}
{
vtkNew<vtkEventDataMove3D> ed;
ed->SetDevice(vtkEventDataDevice::RightController);
this->CallbackMapper->SetCallbackMethod(vtkCommand::Move3DEvent,
ed.Get(), vtkWidgetEvent::Move3D,
this, vtkHandleWidget::MoveAction3D);
}
this->EnableAxisConstraint = 1;
this->EnableTranslation = 1;
this->AllowHandleResize = 1;
......@@ -122,6 +152,34 @@ void vtkHandleWidget::SelectAction(vtkAbstractWidget *w)
self->GenericAction(self);
}
//-------------------------------------------------------------------------
void vtkHandleWidget::SelectAction3D(vtkAbstractWidget *w)
{
vtkHandleWidget *self = reinterpret_cast<vtkHandleWidget*>(w);
self->WidgetRep->ComputeComplexInteractionState(
self->Interactor, self, vtkWidgetEvent::Select3D, self->CallData);
if ( self->WidgetRep->GetInteractionState() == vtkHandleRepresentation::Outside )
{
return;
}
// We are definitely selected
if ( ! self->Parent )
{
self->GrabFocus(self->EventCallbackCommand);
}
self->WidgetRep->StartComplexInteraction(
self->Interactor, self, vtkWidgetEvent::Select3D, self->CallData);
self->WidgetState = vtkHandleWidget::Active;
reinterpret_cast<vtkHandleRepresentation*>(self->WidgetRep)->
SetInteractionState(vtkHandleRepresentation::Selecting);
self->GenericAction(self);
}
//-------------------------------------------------------------------------
void vtkHandleWidget::TranslateAction(vtkAbstractWidget *w)
{
......@@ -130,8 +188,8 @@ void vtkHandleWidget::TranslateAction(vtkAbstractWidget *w)
double eventPos[2];
eventPos[0] = static_cast<double>(self->Interactor->GetEventPosition()[0]);
eventPos[1] = static_cast<double>(self->Interactor->GetEventPosition()[1]);
self->WidgetRep->StartWidgetInteraction(eventPos);
if ( self->WidgetRep->GetInteractionState() == vtkHandleRepresentation::Outside )
{
return;
......@@ -268,6 +326,39 @@ void vtkHandleWidget::MoveAction(vtkAbstractWidget *w)
self->Render();
}
//-------------------------------------------------------------------------
void vtkHandleWidget::MoveAction3D(vtkAbstractWidget *w)
{
vtkHandleWidget *self = reinterpret_cast<vtkHandleWidget*>(w);
// Set the cursor appropriately
if ( self->WidgetState == vtkHandleWidget::Start )
{
int state = self->WidgetRep->GetInteractionState();
self->WidgetRep->ComputeComplexInteractionState(
self->Interactor, self, vtkWidgetEvent::Move3D, self->CallData);
self->SetCursor(self->WidgetRep->GetInteractionState());
// Must rerender if we change appearance
if ( reinterpret_cast<vtkHandleRepresentation*>(self->WidgetRep)->GetActiveRepresentation() &&
state != self->WidgetRep->GetInteractionState() )
{
self->Render();
}
return;
}
// Okay, adjust the representation
self->WidgetRep->ComplexInteraction(
self->Interactor, self, vtkWidgetEvent::Move3D, self->CallData);
// Got this event, we are finished
self->EventCallbackCommand->SetAbortFlag(1);
self->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
self->Render();
}
//----------------------------------------------------------------------------------
void vtkHandleWidget::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -157,6 +157,8 @@ protected:
static void TranslateAction(vtkAbstractWidget*);
static void ScaleAction(vtkAbstractWidget*);
static void MoveAction(vtkAbstractWidget*);
static void SelectAction3D(vtkAbstractWidget*);
static void MoveAction3D(vtkAbstractWidget*);
// helper methods for cursor management
void SetCursor(int state) VTK_OVERRIDE;
......
......@@ -14,6 +14,7 @@
=========================================================================*/
#include "vtkPointHandleRepresentation3D.h"
#include "vtkCursor3D.h"
#include "vtkEventData.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkCellPicker.h"
......@@ -214,6 +215,42 @@ int vtkPointHandleRepresentation3D
return this->InteractionState;
}
int vtkPointHandleRepresentation3D::ComputeComplexInteractionState(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long , void *calldata, int )
{
this->VisibilityOn(); //actor must be on to be picked
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
double pos[3];
edd->GetWorldPosition(pos);
vtkAssemblyPath* path = this->GetAssemblyPath3DPoint(pos, this->CursorPicker);
double focus[3];
this->Cursor3D->GetFocalPoint(focus);
double d[3];
this->GetDisplayPosition(d);
if ( path != nullptr )
{
this->InteractionState = vtkHandleRepresentation::Nearby;
}
else
{
this->InteractionState = vtkHandleRepresentation::Outside;
if ( this->ActiveRepresentation )
{
this->VisibilityOff();
}
}
}
return this->InteractionState;
}
//-------------------------------------------------------------------------
int vtkPointHandleRepresentation3D::DetermineConstraintAxis(
int constraint, double *x, double *startPickPoint)
......@@ -292,6 +329,38 @@ void vtkPointHandleRepresentation3D::StartWidgetInteraction(double startEventPos
this->WaitCount = 0;
}
void vtkPointHandleRepresentation3D::StartComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long, void *calldata)
{
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
edd->GetWorldPosition(this->StartEventPosition);
this->LastEventPosition[0] = this->StartEventPosition[0];
this->LastEventPosition[1] = this->StartEventPosition[1];
this->LastEventPosition[2] = this->StartEventPosition[2];
vtkAssemblyPath* path = this->GetAssemblyPath3DPoint(
this->StartEventPosition, this->CursorPicker);
if ( path != nullptr )
{
this->InteractionState = vtkHandleRepresentation::Nearby;
this->ConstraintAxis = -1;
this->CursorPicker->GetPickPosition(this->LastPickPosition);
}
else
{
this->InteractionState = vtkHandleRepresentation::Outside;
this->ConstraintAxis = -1;
}
this->Cursor3D->SetTranslationMode(this->TranslationMode);
this->WaitCount = 0;
}
}
//----------------------------------------------------------------------
// Based on the displacement vector (computed in display coordinates) and
......@@ -477,6 +546,52 @@ void vtkPointHandleRepresentation3D::WidgetInteraction(double eventPos[2])
this->Modified();
}
void vtkPointHandleRepresentation3D::ComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,