You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
577 lines
18 KiB
C++
577 lines
18 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkAngleWidget.cxx,v
|
|
|
|
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 "vtkAngleWidget.h"
|
|
#include "vtkAngleRepresentation2D.h"
|
|
#include "vtkCallbackCommand.h"
|
|
#include "vtkRenderWindowInteractor.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkRenderer.h"
|
|
#include "vtkHandleWidget.h"
|
|
#include "vtkHandleRepresentation.h"
|
|
#include "vtkCoordinate.h"
|
|
#include "vtkWidgetCallbackMapper.h"
|
|
#include "vtkWidgetEvent.h"
|
|
#include "vtkWidgetEventTranslator.h"
|
|
|
|
vtkStandardNewMacro(vtkAngleWidget);
|
|
|
|
// The angle widget observes the handles.
|
|
// Here we create the command/observer classes to respond to the
|
|
// slider widgets.
|
|
class vtkAngleWidgetCallback : public vtkCommand
|
|
{
|
|
public:
|
|
static vtkAngleWidgetCallback *New()
|
|
{ return new vtkAngleWidgetCallback; }
|
|
void Execute(vtkObject*, unsigned long eventId, void*) VTK_OVERRIDE
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case vtkCommand::StartInteractionEvent:
|
|
this->AngleWidget->StartAngleInteraction(this->HandleNumber);
|
|
break;
|
|
case vtkCommand::InteractionEvent:
|
|
this->AngleWidget->AngleInteraction(this->HandleNumber);
|
|
break;
|
|
case vtkCommand::EndInteractionEvent:
|
|
this->AngleWidget->EndAngleInteraction(this->HandleNumber);
|
|
break;
|
|
}
|
|
}
|
|
int HandleNumber;
|
|
vtkAngleWidget *AngleWidget;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
vtkAngleWidget::vtkAngleWidget()
|
|
{
|
|
this->ManagesCursor = 0;
|
|
|
|
this->WidgetState = vtkAngleWidget::Start;
|
|
this->CurrentHandle = 0;
|
|
|
|
// The widgets for moving the end points. They observe this widget (i.e.,
|
|
// this widget is the parent to the handles).
|
|
this->Point1Widget = vtkHandleWidget::New();
|
|
this->Point1Widget->SetParent(this);
|
|
this->CenterWidget = vtkHandleWidget::New();
|
|
this->CenterWidget->SetParent(this);
|
|
this->Point2Widget = vtkHandleWidget::New();
|
|
this->Point2Widget->SetParent(this);
|
|
|
|
// Set up the callbacks on the two handles
|
|
this->AngleWidgetCallback1 = vtkAngleWidgetCallback::New();
|
|
this->AngleWidgetCallback1->HandleNumber = 0;
|
|
this->AngleWidgetCallback1->AngleWidget = this;
|
|
this->Point1Widget->AddObserver(vtkCommand::StartInteractionEvent, this->AngleWidgetCallback1,
|
|
this->Priority);
|
|
this->Point1Widget->AddObserver(vtkCommand::InteractionEvent, this->AngleWidgetCallback1,
|
|
this->Priority);
|
|
this->Point1Widget->AddObserver(vtkCommand::EndInteractionEvent, this->AngleWidgetCallback1,
|
|
this->Priority);
|
|
|
|
// Set up the callbacks on the two handles
|
|
this->AngleWidgetCenterCallback = vtkAngleWidgetCallback::New();
|
|
this->AngleWidgetCenterCallback->HandleNumber = 1;
|
|
this->AngleWidgetCenterCallback->AngleWidget = this;
|
|
this->CenterWidget->AddObserver(vtkCommand::StartInteractionEvent, this->AngleWidgetCenterCallback,
|
|
this->Priority);
|
|
this->CenterWidget->AddObserver(vtkCommand::InteractionEvent, this->AngleWidgetCenterCallback,
|
|
this->Priority);
|
|
this->CenterWidget->AddObserver(vtkCommand::EndInteractionEvent, this->AngleWidgetCenterCallback,
|
|
this->Priority);
|
|
|
|
this->AngleWidgetCallback2 = vtkAngleWidgetCallback::New();
|
|
this->AngleWidgetCallback2->HandleNumber = 2;
|
|
this->AngleWidgetCallback2->AngleWidget = this;
|
|
this->Point2Widget->AddObserver(vtkCommand::StartInteractionEvent, this->AngleWidgetCallback2,
|
|
this->Priority);
|
|
this->Point2Widget->AddObserver(vtkCommand::InteractionEvent, this->AngleWidgetCallback2,
|
|
this->Priority);
|
|
this->Point2Widget->AddObserver(vtkCommand::EndInteractionEvent, this->AngleWidgetCallback2,
|
|
this->Priority);
|
|
|
|
|
|
// These are the event callbacks supported by this widget
|
|
this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent,
|
|
vtkWidgetEvent::AddPoint,
|
|
this, vtkAngleWidget::AddPointAction);
|
|
this->CallbackMapper->SetCallbackMethod(vtkCommand::MouseMoveEvent,
|
|
vtkWidgetEvent::Move,
|
|
this, vtkAngleWidget::MoveAction);
|
|
this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent,
|
|
vtkWidgetEvent::EndSelect,
|
|
this, vtkAngleWidget::EndSelectAction);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
vtkAngleWidget::~vtkAngleWidget()
|
|
{
|
|
this->Point1Widget->RemoveObserver(this->AngleWidgetCallback1);
|
|
this->Point1Widget->Delete();
|
|
this->AngleWidgetCallback1->Delete();
|
|
|
|
this->CenterWidget->RemoveObserver(this->AngleWidgetCenterCallback);
|
|
this->CenterWidget->Delete();
|
|
this->AngleWidgetCenterCallback->Delete();
|
|
|
|
this->Point2Widget->RemoveObserver(this->AngleWidgetCallback2);
|
|
this->Point2Widget->Delete();
|
|
this->AngleWidgetCallback2->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::CreateDefaultRepresentation()
|
|
{
|
|
if ( ! this->WidgetRep )
|
|
{
|
|
this->WidgetRep = vtkAngleRepresentation2D::New();
|
|
}
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
InstantiateHandleRepresentation();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::SetEnabled(int enabling)
|
|
{
|
|
// The handle widgets are not actually enabled until they are placed.
|
|
// The handle widgets take their representation from the vtkAngleRepresentation.
|
|
if ( enabling )
|
|
{
|
|
if ( this->WidgetState == vtkAngleWidget::Start )
|
|
{
|
|
if (this->WidgetRep)
|
|
{
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
Ray1VisibilityOff();
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
Ray2VisibilityOff();
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
ArcVisibilityOff();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this->WidgetRep)
|
|
{
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
Ray1VisibilityOn();
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
Ray2VisibilityOn();
|
|
reinterpret_cast<vtkAngleRepresentation*>(this->WidgetRep)->
|
|
ArcVisibilityOn();
|
|
}
|
|
|
|
// The interactor must be set prior to enabling the widget.
|
|
if (this->Interactor)
|
|
{
|
|
this->Point1Widget->SetInteractor(this->Interactor);
|
|
this->CenterWidget->SetInteractor(this->Interactor);
|
|
this->Point2Widget->SetInteractor(this->Interactor);
|
|
}
|
|
|
|
this->Point1Widget->SetEnabled(1);
|
|
this->CenterWidget->SetEnabled(1);
|
|
this->Point2Widget->SetEnabled(1);
|
|
}
|
|
}
|
|
|
|
|
|
if ( enabling ) //----------------
|
|
{
|
|
if ( this->Enabled ) //already enabled, just return
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( ! this->Interactor )
|
|
{
|
|
vtkErrorMacro(<<"The interactor must be set prior to enabling the widget");
|
|
return;
|
|
}
|
|
|
|
int X=this->Interactor->GetEventPosition()[0];
|
|
int Y=this->Interactor->GetEventPosition()[1];
|
|
|
|
if ( ! this->CurrentRenderer )
|
|
{
|
|
this->SetCurrentRenderer(this->Interactor->FindPokedRenderer(X,Y));
|
|
|
|
if (this->CurrentRenderer == NULL)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We're ready to enable
|
|
this->Enabled = 1;
|
|
this->CreateDefaultRepresentation();
|
|
this->WidgetRep->SetRenderer(this->CurrentRenderer);
|
|
|
|
// listen for the events found in the EventTranslator
|
|
if ( ! this->Parent )
|
|
{
|
|
this->EventTranslator->AddEventsToInteractor(this->Interactor,
|
|
this->EventCallbackCommand,this->Priority);
|
|
}
|
|
else
|
|
{
|
|
this->EventTranslator->AddEventsToParent(this->Parent,
|
|
this->EventCallbackCommand,this->Priority);
|
|
}
|
|
|
|
if ( this->ManagesCursor )
|
|
{
|
|
this->WidgetRep->ComputeInteractionState(X, Y);
|
|
this->SetCursor(this->WidgetRep->GetInteractionState());
|
|
}
|
|
|
|
vtkAngleRepresentation *rep =
|
|
static_cast<vtkAngleRepresentation*>(this->WidgetRep);
|
|
|
|
// Set the renderer, representation and interactor on the child widgets.
|
|
if (this->Point1Widget)
|
|
{
|
|
this->Point1Widget->SetRepresentation(rep->GetPoint1Representation());
|
|
this->Point1Widget->SetInteractor(this->Interactor);
|
|
this->Point1Widget->GetRepresentation()->SetRenderer(
|
|
this->CurrentRenderer);
|
|
}
|
|
|
|
if (this->CenterWidget)
|
|
{
|
|
this->CenterWidget->SetRepresentation(rep->GetCenterRepresentation());
|
|
this->CenterWidget->SetInteractor(this->Interactor);
|
|
this->CenterWidget->GetRepresentation()->SetRenderer(
|
|
this->CurrentRenderer);
|
|
}
|
|
|
|
if (this->Point2Widget)
|
|
{
|
|
this->Point2Widget->SetRepresentation(rep->GetPoint2Representation());
|
|
this->Point2Widget->SetInteractor(this->Interactor);
|
|
this->Point2Widget->GetRepresentation()->SetRenderer(
|
|
this->CurrentRenderer);
|
|
}
|
|
|
|
if (rep)
|
|
{
|
|
rep->SetRay1Visibility(
|
|
this->WidgetState != vtkAngleWidget::Start ? 1 : 0);
|
|
rep->SetRay2Visibility(
|
|
this->WidgetState != vtkAngleWidget::Start ? 1 : 0);
|
|
rep->SetArcVisibility(
|
|
this->WidgetState != vtkAngleWidget::Start ? 1 : 0);
|
|
}
|
|
|
|
|
|
if ( this->WidgetState != vtkAngleWidget::Start )
|
|
{
|
|
if (this->Point1Widget)
|
|
{
|
|
this->Point1Widget->SetEnabled(1);
|
|
}
|
|
if (this->CenterWidget)
|
|
{
|
|
this->CenterWidget->SetEnabled(1);
|
|
}
|
|
if (this->Point2Widget)
|
|
{
|
|
this->Point2Widget->SetEnabled(1);
|
|
}
|
|
}
|
|
|
|
this->WidgetRep->BuildRepresentation();
|
|
this->CurrentRenderer->AddViewProp(this->WidgetRep);
|
|
|
|
this->InvokeEvent(vtkCommand::EnableEvent,NULL);
|
|
}
|
|
|
|
else //disabling------------------
|
|
{
|
|
if ( ! this->Enabled ) //already disabled, just return
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Enabled = 0;
|
|
|
|
// don't listen for events any more
|
|
if ( ! this->Parent )
|
|
{
|
|
this->Interactor->RemoveObserver(this->EventCallbackCommand);
|
|
}
|
|
else
|
|
{
|
|
this->Parent->RemoveObserver(this->EventCallbackCommand);
|
|
}
|
|
|
|
this->CurrentRenderer->RemoveViewProp(this->WidgetRep);
|
|
|
|
|
|
if (vtkAngleRepresentation *rep =
|
|
static_cast<vtkAngleRepresentation*>(this->WidgetRep))
|
|
{
|
|
rep->Ray1VisibilityOff();
|
|
rep->Ray2VisibilityOff();
|
|
rep->ArcVisibilityOff();
|
|
}
|
|
|
|
if (this->Point1Widget)
|
|
{
|
|
this->Point1Widget->SetEnabled(0);
|
|
}
|
|
|
|
if (this->CenterWidget)
|
|
{
|
|
this->CenterWidget->SetEnabled(0);
|
|
}
|
|
|
|
if (this->Point2Widget)
|
|
{
|
|
this->Point2Widget->SetEnabled(0);
|
|
}
|
|
|
|
this->InvokeEvent(vtkCommand::DisableEvent,NULL);
|
|
this->SetCurrentRenderer(NULL);
|
|
}
|
|
|
|
|
|
// Should only render if there is no parent
|
|
if ( this->Interactor && !this->Parent )
|
|
{
|
|
this->Interactor->Render();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
int vtkAngleWidget::IsAngleValid()
|
|
{
|
|
if ( this->WidgetState == vtkAngleWidget::Manipulate ||
|
|
(this->WidgetState == vtkAngleWidget::Define && this->CurrentHandle == 2) )
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// The following methods are the callbacks that the angle widget responds to.
|
|
//-------------------------------------------------------------------------
|
|
void vtkAngleWidget::AddPointAction(vtkAbstractWidget *w)
|
|
{
|
|
vtkAngleWidget *self = reinterpret_cast<vtkAngleWidget*>(w);
|
|
int X = self->Interactor->GetEventPosition()[0];
|
|
int Y = self->Interactor->GetEventPosition()[1];
|
|
|
|
// If we are placing the first point it's easy
|
|
if ( self->WidgetState == vtkAngleWidget::Start )
|
|
{
|
|
self->GrabFocus(self->EventCallbackCommand);
|
|
self->WidgetState = vtkAngleWidget::Define;
|
|
self->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
|
|
double e[2];
|
|
e[0] = static_cast<double>(X);
|
|
e[1] = static_cast<double>(Y);
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->StartWidgetInteraction(e);
|
|
self->CurrentHandle = 0;
|
|
self->InvokeEvent(vtkCommand::PlacePointEvent,&(self->CurrentHandle));
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->Ray1VisibilityOn();
|
|
self->Point1Widget->SetEnabled(1);
|
|
self->CurrentHandle++;
|
|
}
|
|
|
|
// If defining we are placing the second or third point
|
|
else if ( self->WidgetState == vtkAngleWidget::Define )
|
|
{
|
|
self->InvokeEvent(vtkCommand::PlacePointEvent,&(self->CurrentHandle));
|
|
if ( self->CurrentHandle == 1 )
|
|
{
|
|
double e[2];
|
|
e[0] = static_cast<double>(X);
|
|
e[1] = static_cast<double>(Y);
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->CenterWidgetInteraction(e);
|
|
self->CurrentHandle++;
|
|
self->CenterWidget->SetEnabled(1);
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->Ray2VisibilityOn();
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->ArcVisibilityOn();
|
|
}
|
|
else if ( self->CurrentHandle == 2 )
|
|
{
|
|
self->WidgetState = vtkAngleWidget::Manipulate;
|
|
self->Point2Widget->SetEnabled(1);
|
|
self->CurrentHandle = (-1);
|
|
self->ReleaseFocus();
|
|
self->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
|
|
}
|
|
}
|
|
|
|
// Maybe we are trying to manipulate the widget handles
|
|
else //if ( self->WidgetState == vtkAngleWidget::Manipulate )
|
|
{
|
|
int state = self->WidgetRep->ComputeInteractionState(X,Y);
|
|
if ( state == vtkAngleRepresentation::Outside )
|
|
{
|
|
self->CurrentHandle = (-1);
|
|
return;
|
|
}
|
|
|
|
self->GrabFocus(self->EventCallbackCommand);
|
|
if ( state == vtkAngleRepresentation::NearP1 )
|
|
{
|
|
self->CurrentHandle = 0;
|
|
}
|
|
else if ( state == vtkAngleRepresentation::NearCenter )
|
|
{
|
|
self->CurrentHandle = 1;
|
|
}
|
|
else if ( state == vtkAngleRepresentation::NearP2 )
|
|
{
|
|
self->CurrentHandle = 2;
|
|
}
|
|
self->InvokeEvent(vtkCommand::LeftButtonPressEvent,NULL);
|
|
}
|
|
|
|
self->EventCallbackCommand->SetAbortFlag(1);
|
|
self->Render();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void vtkAngleWidget::MoveAction(vtkAbstractWidget *w)
|
|
{
|
|
vtkAngleWidget *self = reinterpret_cast<vtkAngleWidget*>(w);
|
|
|
|
// Do nothing if outside
|
|
if ( self->WidgetState == vtkAngleWidget::Start )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Delegate the event consistent with the state
|
|
if ( self->WidgetState == vtkAngleWidget::Define )
|
|
{
|
|
int X = self->Interactor->GetEventPosition()[0];
|
|
int Y = self->Interactor->GetEventPosition()[1];
|
|
double e[2];
|
|
e[0] = static_cast<double>(X);
|
|
e[1] = static_cast<double>(Y);
|
|
if ( self->CurrentHandle == 1 )
|
|
{
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->
|
|
CenterWidgetInteraction(e);
|
|
}
|
|
else
|
|
{
|
|
reinterpret_cast<vtkAngleRepresentation*>(self->WidgetRep)->
|
|
WidgetInteraction(e);
|
|
}
|
|
self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
|
|
self->EventCallbackCommand->SetAbortFlag(1);
|
|
}
|
|
|
|
else //must be moving a handle, invoke a event for the handle widgets
|
|
{
|
|
self->InvokeEvent(vtkCommand::MouseMoveEvent, NULL);
|
|
}
|
|
|
|
self->WidgetRep->BuildRepresentation();
|
|
self->Render();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void vtkAngleWidget::EndSelectAction(vtkAbstractWidget *w)
|
|
{
|
|
vtkAngleWidget *self = reinterpret_cast<vtkAngleWidget*>(w);
|
|
|
|
// Do nothing if outside
|
|
if ( self->WidgetState == vtkAngleWidget::Start ||
|
|
self->WidgetState == vtkAngleWidget::Define ||
|
|
self->CurrentHandle < 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self->ReleaseFocus();
|
|
self->InvokeEvent(vtkCommand::LeftButtonReleaseEvent,NULL);
|
|
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 angle widget.
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::StartAngleInteraction(int)
|
|
{
|
|
this->Superclass::StartInteraction();
|
|
this->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::AngleInteraction(int)
|
|
{
|
|
this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::EndAngleInteraction(int)
|
|
{
|
|
this->Superclass::EndInteraction();
|
|
|
|
this->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::SetProcessEvents(int pe)
|
|
{
|
|
this->Superclass::SetProcessEvents(pe);
|
|
|
|
//Pass pe flag to component widgets.
|
|
this->Point1Widget->SetProcessEvents(pe);
|
|
this->CenterWidget->SetProcessEvents(pe);
|
|
this->Point2Widget->SetProcessEvents(pe);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::SetWidgetStateToStart()
|
|
{
|
|
this->WidgetState = vtkAngleWidget::Start;
|
|
this->CurrentHandle = -1;
|
|
this->ReleaseFocus();
|
|
this->GetRepresentation()->BuildRepresentation(); // update this->Angle
|
|
this->SetEnabled(this->GetEnabled()); // show/hide the handles properly
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::SetWidgetStateToManipulate()
|
|
{
|
|
this->WidgetState = vtkAngleWidget::Manipulate;
|
|
this->CurrentHandle = -1;
|
|
this->ReleaseFocus();
|
|
this->GetRepresentation()->BuildRepresentation(); // update this->Angle
|
|
this->SetEnabled(this->GetEnabled()); // show/hide the handles properly
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void vtkAngleWidget::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
//Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
|
|
this->Superclass::PrintSelf(os,indent);
|
|
}
|