/*========================================================================= Program: Visualization Toolkit Module: vtkSeedWidget.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. =========================================================================*/ #include "vtkSeedWidget.h" #include "vtkCallbackCommand.h" #include "vtkCommand.h" #include "vtkCoordinate.h" #include "vtkEvent.h" #include "vtkHandleRepresentation.h" #include "vtkHandleWidget.h" #include "vtkObjectFactory.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkSeedRepresentation.h" #include "vtkWidgetCallbackMapper.h" #include "vtkWidgetEvent.h" #include #include vtkStandardNewMacro(vtkSeedWidget); // The vtkSeedList is a PIMPLed list. class vtkSeedList : public std::list {}; typedef std::list::iterator vtkSeedListIterator; //---------------------------------------------------------------------- vtkSeedWidget::vtkSeedWidget() { this->ManagesCursor = 1; this->WidgetState = vtkSeedWidget::Start; // The widgets for moving the seeds. this->Seeds = new vtkSeedList; // These are the event callbacks supported by this widget this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkWidgetEvent::AddPoint, this, vtkSeedWidget::AddPointAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonPressEvent, vtkWidgetEvent::Completed, this, vtkSeedWidget::CompletedAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::MouseMoveEvent, vtkWidgetEvent::Move, this, vtkSeedWidget::MoveAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent, vtkWidgetEvent::EndSelect, this, vtkSeedWidget::EndSelectAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::NoModifier, 127, 1, "Delete", vtkWidgetEvent::Delete, this, vtkSeedWidget::DeleteAction); this->Defining = 1; } //---------------------------------------------------------------------- void vtkSeedWidget::DeleteSeed(int i) { if( this->Seeds->size() <= static_cast< size_t >(i) ) { return; } vtkSeedRepresentation *rep = static_cast(this->WidgetRep); if (rep) { rep->RemoveHandle( i ); } vtkSeedListIterator iter = this->Seeds->begin(); std::advance(iter,i); (*iter)->SetEnabled(0); (*iter)->RemoveObservers(vtkCommand::StartInteractionEvent); (*iter)->RemoveObservers(vtkCommand::InteractionEvent); (*iter)->RemoveObservers(vtkCommand::EndInteractionEvent); vtkHandleWidget * w = (*iter); this->Seeds->erase( iter ); w->Delete(); } //---------------------------------------------------------------------- vtkSeedWidget::~vtkSeedWidget() { // Loop over all seeds releasing their observers and deleting them while( !this->Seeds->empty() ) { this->DeleteSeed(static_cast(this->Seeds->size())-1); } delete this->Seeds; } //---------------------------------------------------------------------- vtkHandleWidget * vtkSeedWidget::GetSeed(int i) { if( this->Seeds->size() <= static_cast< size_t >(i) ) { return nullptr; } vtkSeedListIterator iter = this->Seeds->begin(); std::advance(iter,i); return *iter; } //---------------------------------------------------------------------- void vtkSeedWidget::CreateDefaultRepresentation() { if ( ! this->WidgetRep ) { this->WidgetRep = vtkSeedRepresentation::New(); } } //---------------------------------------------------------------------- void vtkSeedWidget::SetEnabled(int enabling) { this->Superclass::SetEnabled( enabling ); vtkSeedListIterator iter; for ( iter = this->Seeds->begin(); iter != this->Seeds->end(); ++iter ) { (*iter)->SetEnabled( enabling ); } if ( !enabling ) { this->RequestCursorShape( VTK_CURSOR_DEFAULT ); this->WidgetState = vtkSeedWidget::Start; } this->Render(); } // The following methods are the callbacks that the seed widget responds to. //------------------------------------------------------------------------- void vtkSeedWidget::AddPointAction(vtkAbstractWidget *w) { vtkSeedWidget *self = reinterpret_cast(w); // Need to distinguish between placing handles and manipulating handles if ( self->WidgetState == vtkSeedWidget::MovingSeed ) { return; } // compute some info we need for all cases int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; // When a seed is placed, a new handle widget must be created and enabled. int state = self->WidgetRep->ComputeInteractionState(X,Y); if ( state == vtkSeedRepresentation::NearSeed ) { self->WidgetState = vtkSeedWidget::MovingSeed; // Invoke an event on ourself for the handles self->InvokeEvent(vtkCommand::LeftButtonPressEvent,nullptr); self->Superclass::StartInteraction(); vtkSeedRepresentation *rep = static_cast< vtkSeedRepresentation * >(self->WidgetRep); int seedIdx = rep->GetActiveHandle(); self->InvokeEvent(vtkCommand::StartInteractionEvent, &seedIdx); self->EventCallbackCommand->SetAbortFlag(1); self->Render(); } else if ( self->WidgetState != vtkSeedWidget::PlacedSeeds) { // we are placing a new seed. Just make sure we aren't in a mode which // dictates we've placed all seeds. self->WidgetState = vtkSeedWidget::PlacingSeeds; double e[3]; e[2]=0.0; e[0] = static_cast(X); e[1] = static_cast(Y); vtkSeedRepresentation *rep = reinterpret_cast(self->WidgetRep); // if the handle representation is constrained, check to see if // the position follows the constraint. if ( !rep->GetHandleRepresentation()->CheckConstraint( self->GetCurrentRenderer(), e ) ) { return ; } int currentHandleNumber = rep->CreateHandle(e); vtkHandleWidget *currentHandle = self->CreateNewHandle(); rep->SetSeedDisplayPosition(currentHandleNumber,e); currentHandle->SetEnabled(1); self->InvokeEvent(vtkCommand::PlacePointEvent,&(currentHandleNumber)); self->InvokeEvent(vtkCommand::InteractionEvent,&(currentHandleNumber)); self->EventCallbackCommand->SetAbortFlag(1); self->Render(); } } //------------------------------------------------------------------------- void vtkSeedWidget::CompletedAction(vtkAbstractWidget *w) { vtkSeedWidget *self = reinterpret_cast(w); // Do something only if we are in the middle of placing the seeds if ( self->WidgetState == vtkSeedWidget::PlacingSeeds ) { self->CompleteInteraction(); } } //------------------------------------------------------------------------- void vtkSeedWidget::CompleteInteraction() { this->WidgetState = vtkSeedWidget::PlacedSeeds; this->EventCallbackCommand->SetAbortFlag(1); this->Defining = 0; } //------------------------------------------------------------------------- void vtkSeedWidget::RestartInteraction() { this->WidgetState = vtkSeedWidget::Start; this->Defining = 1; } //------------------------------------------------------------------------- void vtkSeedWidget::MoveAction(vtkAbstractWidget *w) { vtkSeedWidget *self = reinterpret_cast(w); self->InvokeEvent(vtkCommand::MouseMoveEvent, nullptr); // set the cursor shape to a hand if we are near a seed. int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; int state = self->WidgetRep->ComputeInteractionState(X,Y); // Change the cursor shape to a hand and invoke an interaction event if we // are near the seed if (state == vtkSeedRepresentation::NearSeed) { self->RequestCursorShape( VTK_CURSOR_HAND ); vtkSeedRepresentation *rep = static_cast< vtkSeedRepresentation * >(self->WidgetRep); int seedIdx = rep->GetActiveHandle(); self->InvokeEvent( vtkCommand::InteractionEvent, &seedIdx ); self->EventCallbackCommand->SetAbortFlag(1); } else { self->RequestCursorShape( VTK_CURSOR_DEFAULT ); } self->Render(); } //------------------------------------------------------------------------- void vtkSeedWidget::EndSelectAction(vtkAbstractWidget *w) { vtkSeedWidget *self = reinterpret_cast(w); // Do nothing if outside if ( self->WidgetState != vtkSeedWidget::MovingSeed ) { return; } // Revert back to the mode we were in prior to selection. self->WidgetState = self->Defining ? vtkSeedWidget::PlacingSeeds : vtkSeedWidget::PlacedSeeds; // Invoke event for seed handle self->InvokeEvent(vtkCommand::LeftButtonReleaseEvent,nullptr); self->EventCallbackCommand->SetAbortFlag(1); self->InvokeEvent(vtkCommand::EndInteractionEvent,nullptr); self->Superclass::EndInteraction(); self->Render(); } //------------------------------------------------------------------------- void vtkSeedWidget::DeleteAction(vtkAbstractWidget *w) { vtkSeedWidget *self = reinterpret_cast(w); // Do nothing if outside if ( self->WidgetState != vtkSeedWidget::PlacingSeeds ) { return; } // Remove last seed vtkSeedRepresentation *rep = reinterpret_cast(self->WidgetRep); int removeId = rep->GetActiveHandle(); removeId = removeId != -1 ? removeId : static_cast(self->Seeds->size()) - 1; // Invoke event for seed handle before actually deleting self->InvokeEvent(vtkCommand::DeletePointEvent, &(removeId)); rep->RemoveHandle(removeId); self->DeleteSeed(removeId); // Got this event, abort processing if it self->EventCallbackCommand->SetAbortFlag(1); self->Render(); } //---------------------------------------------------------------------- void vtkSeedWidget::SetProcessEvents(int pe) { this->Superclass::SetProcessEvents(pe); vtkSeedListIterator iter = this->Seeds->begin(); for (; iter != this->Seeds->end(); ++iter ) { (*iter)->SetProcessEvents(pe); } } //---------------------------------------------------------------------- void vtkSeedWidget::SetInteractor( vtkRenderWindowInteractor *rwi ) { this->Superclass::SetInteractor(rwi); vtkSeedListIterator iter = this->Seeds->begin(); for (; iter != this->Seeds->end(); ++iter ) { (*iter)->SetInteractor(rwi); } } //---------------------------------------------------------------------- void vtkSeedWidget::SetCurrentRenderer( vtkRenderer *ren ) { this->Superclass::SetCurrentRenderer(ren); vtkSeedListIterator iter = this->Seeds->begin(); for (; iter != this->Seeds->end(); ++iter ) { if (!ren) { // Disable widget if its being removed from the the renderer (*iter)->EnabledOff(); } (*iter)->SetCurrentRenderer(ren); } } //---------------------------------------------------------------------- // Programmatically create a new handle. vtkHandleWidget * vtkSeedWidget::CreateNewHandle() { vtkSeedRepresentation *rep = vtkSeedRepresentation::SafeDownCast(this->WidgetRep); if (!rep) { vtkErrorMacro( << "Please set, or create a default seed representation " << "before adding requesting creation of a new handle." ); return nullptr; } // Create the handle widget or reuse an old one int currentHandleNumber = static_cast(this->Seeds->size()); vtkHandleWidget *widget = vtkHandleWidget::New(); // Configure the handle widget widget->SetParent(this); widget->SetInteractor(this->Interactor); vtkHandleRepresentation *handleRep = rep->GetHandleRepresentation(currentHandleNumber); if (!handleRep) { widget->Delete(); return nullptr; } else { handleRep->SetRenderer(this->CurrentRenderer); widget->SetRepresentation(handleRep); // Now place the widget into the list of handle widgets (if not already there) this->Seeds->push_back( widget ); return widget; } } //---------------------------------------------------------------------- void vtkSeedWidget::PrintSelf(ostream& os, vtkIndent indent) { //Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h this->Superclass::PrintSelf(os,indent); os << indent << "WidgetState: " << this->WidgetState << endl; }