/*========================================================================= 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*) 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(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(this->WidgetRep)-> Ray1VisibilityOff(); reinterpret_cast(this->WidgetRep)-> Ray2VisibilityOff(); reinterpret_cast(this->WidgetRep)-> ArcVisibilityOff(); } } else { if (this->WidgetRep) { reinterpret_cast(this->WidgetRep)-> Ray1VisibilityOn(); reinterpret_cast(this->WidgetRep)-> Ray2VisibilityOn(); reinterpret_cast(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 == nullptr) { 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(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,nullptr); } 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(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,nullptr); this->SetCurrentRenderer(nullptr); } // 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(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,nullptr); double e[2]; e[0] = static_cast(X); e[1] = static_cast(Y); reinterpret_cast(self->WidgetRep)->StartWidgetInteraction(e); self->CurrentHandle = 0; self->InvokeEvent(vtkCommand::PlacePointEvent,&(self->CurrentHandle)); reinterpret_cast(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(X); e[1] = static_cast(Y); reinterpret_cast(self->WidgetRep)->CenterWidgetInteraction(e); self->CurrentHandle++; self->CenterWidget->SetEnabled(1); reinterpret_cast(self->WidgetRep)->Ray2VisibilityOn(); reinterpret_cast(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,nullptr); } } // 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,nullptr); } self->EventCallbackCommand->SetAbortFlag(1); self->Render(); } //------------------------------------------------------------------------- void vtkAngleWidget::MoveAction(vtkAbstractWidget *w) { vtkAngleWidget *self = reinterpret_cast(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(X); e[1] = static_cast(Y); if ( self->CurrentHandle == 1 ) { reinterpret_cast(self->WidgetRep)-> CenterWidgetInteraction(e); } else { reinterpret_cast(self->WidgetRep)-> WidgetInteraction(e); } 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::MouseMoveEvent, nullptr); } self->WidgetRep->BuildRepresentation(); self->Render(); } //------------------------------------------------------------------------- void vtkAngleWidget::EndSelectAction(vtkAbstractWidget *w) { vtkAngleWidget *self = reinterpret_cast(w); // Do nothing if outside if ( self->WidgetState == vtkAngleWidget::Start || self->WidgetState == vtkAngleWidget::Define || self->CurrentHandle < 0 ) { return; } self->ReleaseFocus(); self->InvokeEvent(vtkCommand::LeftButtonReleaseEvent,nullptr); 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,nullptr); } //---------------------------------------------------------------------- void vtkAngleWidget::AngleInteraction(int) { this->InvokeEvent(vtkCommand::InteractionEvent,nullptr); } //---------------------------------------------------------------------- void vtkAngleWidget::EndAngleInteraction(int) { this->Superclass::EndInteraction(); this->InvokeEvent(vtkCommand::EndInteractionEvent,nullptr); } //---------------------------------------------------------------------- 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); }