/*========================================================================= 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 "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.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(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(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; } self->InvokeEvent(vtkCommand::MouseMoveEvent, nullptr); // 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(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(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)); self->DeleteSeed(removeId); // Got this event, abort processing if it self->EventCallbackCommand->SetAbortFlag(1); self->Render(); } //------------------------------------------------------------------------------ void vtkSeedWidget::SetProcessEvents(vtkTypeBool 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 it's being removed from 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; }