/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkImagePlaneWidget.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 "vtkImagePlaneWidget.h" #include "vtkActor.h" #include "vtkAssemblyNode.h" #include "vtkAssemblyPath.h" #include "vtkCallbackCommand.h" #include "vtkCamera.h" #include "vtkCellArray.h" #include "vtkCellPicker.h" #include "vtkImageData.h" #include "vtkImageMapToColors.h" #include "vtkImageReslice.h" #include "vtkLookupTable.h" #include "vtkMath.h" #include "vtkMatrix4x4.h" #include "vtkObjectFactory.h" #include "vtkPlaneSource.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkProperty.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkTextActor.h" #include "vtkTextProperty.h" #include "vtkTexture.h" #include "vtkTransform.h" vtkCxxRevisionMacro(vtkImagePlaneWidget, "$Revision: 1.4.2.1 $"); vtkStandardNewMacro(vtkImagePlaneWidget); vtkCxxSetObjectMacro(vtkImagePlaneWidget, PlaneProperty, vtkProperty); vtkCxxSetObjectMacro(vtkImagePlaneWidget, SelectedPlaneProperty, vtkProperty); vtkCxxSetObjectMacro(vtkImagePlaneWidget, CursorProperty, vtkProperty); vtkCxxSetObjectMacro(vtkImagePlaneWidget, MarginProperty, vtkProperty); vtkCxxSetObjectMacro(vtkImagePlaneWidget, TexturePlaneProperty, vtkProperty); vtkCxxSetObjectMacro(vtkImagePlaneWidget, ColorMap, vtkImageMapToColors); vtkImagePlaneWidget::vtkImagePlaneWidget() : vtkPolyDataSourceWidget() { this->State = vtkImagePlaneWidget::Start; this->EventCallbackCommand->SetCallback(vtkImagePlaneWidget::ProcessEvents); this->Interaction = 1; this->PlaneOrientation = 0; this->PlaceFactor = 1.0; this->RestrictPlaneToVolume = 1; this->OriginalWindow = 1.0; this->OriginalLevel = 0.5; this->CurrentWindow = 1.0; this->CurrentLevel = 0.5; this->TextureInterpolate = 1; this->ResliceInterpolate = VTK_LINEAR_RESLICE; this->UserControlledLookupTable= 0; this->DisplayText = 0; this->CurrentCursorPosition[0] = 0; this->CurrentCursorPosition[1] = 0; this->CurrentCursorPosition[2] = 0; this->CurrentImageValue = VTK_DOUBLE_MAX; this->MarginSelectMode = 8; this->UseContinuousCursor = 0; // Represent the plane's outline // this->PlaneSource = vtkPlaneSource::New(); this->PlaneSource->SetXResolution(1); this->PlaneSource->SetYResolution(1); this->PlaneOutlinePolyData = vtkPolyData::New(); this->PlaneOutlineActor = vtkActor::New(); // Represent the resliced image plane // this->ColorMap = vtkImageMapToColors::New(); this->Reslice = vtkImageReslice::New(); this->Reslice->TransformInputSamplingOff(); this->ResliceAxes = vtkMatrix4x4::New(); this->Texture = vtkTexture::New(); this->TexturePlaneActor = vtkActor::New(); this->Transform = vtkTransform::New(); this->ImageData = 0; this->LookupTable = 0; // Represent the cross hair cursor // this->CursorPolyData = vtkPolyData::New(); this->CursorActor = vtkActor::New(); // Represent the oblique positioning margins // this->MarginPolyData = vtkPolyData::New(); this->MarginActor = vtkActor::New(); // Represent the text: annotation for cursor position and W/L // this->TextActor = vtkTextActor::New(); this->GeneratePlaneOutline(); // Define some default point coordinates // double bounds[6]; bounds[0] = -0.5; bounds[1] = 0.5; bounds[2] = -0.5; bounds[3] = 0.5; bounds[4] = -0.5; bounds[5] = 0.5; // Initial creation of the widget, serves to initialize it // this->PlaceWidget(bounds); this->GenerateTexturePlane(); this->GenerateCursor(); this->GenerateMargins(); this->GenerateText(); // Manage the picking stuff // this->PlanePicker = vtkCellPicker::New(); this->PlanePicker->SetTolerance(0.005); //need some fluff this->PlanePicker->AddPickList(this->TexturePlaneActor); this->PlanePicker->PickFromListOn(); this->PlanePicker->Register(this); this->PlanePicker->Delete(); // Set up the initial properties // this->PlaneProperty = 0; this->SelectedPlaneProperty = 0; this->TexturePlaneProperty = 0; this->CursorProperty = 0; this->MarginProperty = 0; this->CreateDefaultProperties(); // Set up actions this->LeftButtonAction = vtkImagePlaneWidget::CURSOR_ACTION; this->MiddleButtonAction = vtkImagePlaneWidget::SLICE_MOTION_ACTION; this->RightButtonAction = vtkImagePlaneWidget::WINDOW_LEVEL_ACTION; // Set up modifiers this->LeftButtonAutoModifier = vtkImagePlaneWidget::NO_MODIFIER; this->MiddleButtonAutoModifier = vtkImagePlaneWidget::NO_MODIFIER; this->RightButtonAutoModifier = vtkImagePlaneWidget::NO_MODIFIER; this->LastButtonPressed = vtkImagePlaneWidget::NO_BUTTON; this->TextureVisibility = 1; } vtkImagePlaneWidget::~vtkImagePlaneWidget() { this->PlaneOutlineActor->Delete(); this->PlaneOutlinePolyData->Delete(); this->PlaneSource->Delete(); if ( this->PlanePicker ) { this->PlanePicker->UnRegister(this); } if ( this->PlaneProperty ) { this->PlaneProperty->Delete(); } if ( this->SelectedPlaneProperty ) { this->SelectedPlaneProperty->Delete(); } if ( this->CursorProperty ) { this->CursorProperty->Delete(); } if ( this->MarginProperty ) { this->MarginProperty->Delete(); } this->ResliceAxes->Delete(); this->Transform->Delete(); this->Reslice->Delete(); if ( this->LookupTable ) { this->LookupTable->UnRegister(this); } this->TexturePlaneActor->Delete(); this->ColorMap->Delete(); this->Texture->Delete(); if ( this->TexturePlaneProperty ) { this->TexturePlaneProperty->Delete(); } if ( this->ImageData ) { this->ImageData = 0; } this->CursorActor->Delete(); this->CursorPolyData->Delete(); this->MarginActor->Delete(); this->MarginPolyData->Delete(); this->TextActor->Delete(); } void vtkImagePlaneWidget::SetTextureVisibility(int vis) { if (this->TextureVisibility == vis) { return; } this->TextureVisibility = vis; if ( this->Enabled ) { if (this->TextureVisibility) { this->CurrentRenderer->AddViewProp(this->TexturePlaneActor); } else { this->CurrentRenderer->RemoveViewProp(this->TexturePlaneActor); } } this->Modified(); } void vtkImagePlaneWidget::SetEnabled(int enabling) { if ( ! this->Interactor ) { vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget"); return; } if ( enabling ) //---------------------------------------------------------- { vtkDebugMacro(<<"Enabling plane widget"); if ( this->Enabled ) //already enabled, just return { return; } if ( ! this->CurrentRenderer ) { this->SetCurrentRenderer(this->Interactor->FindPokedRenderer( this->Interactor->GetLastEventPosition()[0], this->Interactor->GetLastEventPosition()[1])); if (this->CurrentRenderer == NULL) { return; } } this->Enabled = 1; // we have to honour this ivar: it could be that this->Interaction was // set to off when we were disabled if (this->Interaction) { this->AddObservers(); } // Add the plane this->CurrentRenderer->AddViewProp(this->PlaneOutlineActor); this->PlaneOutlineActor->SetProperty(this->PlaneProperty); //add the TexturePlaneActor if (this->TextureVisibility) { this->CurrentRenderer->AddViewProp(this->TexturePlaneActor); } this->TexturePlaneActor->SetProperty(this->TexturePlaneProperty); // Add the cross-hair cursor this->CurrentRenderer->AddViewProp(this->CursorActor); this->CursorActor->SetProperty(this->CursorProperty); // Add the margins this->CurrentRenderer->AddViewProp(this->MarginActor); this->MarginActor->SetProperty(this->MarginProperty); // Add the image data annotation this->CurrentRenderer->AddViewProp(this->TextActor); if ( this->PlanePicker ) { this->TexturePlaneActor->PickableOn(); } this->InvokeEvent(vtkCommand::EnableEvent,0); } else //disabling---------------------------------------------------------- { vtkDebugMacro(<<"Disabling plane widget"); if ( ! this->Enabled ) //already disabled, just return { return; } this->Enabled = 0; // don't listen for events any more this->Interactor->RemoveObserver(this->EventCallbackCommand); // turn off the plane this->CurrentRenderer->RemoveViewProp(this->PlaneOutlineActor); //turn off the texture plane this->CurrentRenderer->RemoveViewProp(this->TexturePlaneActor); //turn off the cursor this->CurrentRenderer->RemoveViewProp(this->CursorActor); //turn off the margins this->CurrentRenderer->RemoveViewProp(this->MarginActor); //turn off the image data annotation this->CurrentRenderer->RemoveViewProp(this->TextActor); if ( this->PlanePicker ) { this->TexturePlaneActor->PickableOff(); } this->InvokeEvent(vtkCommand::DisableEvent,0); this->SetCurrentRenderer(NULL); } this->Interactor->Render(); } void vtkImagePlaneWidget::ProcessEvents(vtkObject* vtkNotUsed(object), unsigned long event, void* clientdata, void* vtkNotUsed(calldata)) { vtkImagePlaneWidget* self = reinterpret_cast( clientdata ); self->LastButtonPressed = vtkImagePlaneWidget::NO_BUTTON; //okay, let's do the right thing switch ( event ) { case vtkCommand::LeftButtonPressEvent: self->LastButtonPressed = vtkImagePlaneWidget::LEFT_BUTTON; self->OnLeftButtonDown(); break; case vtkCommand::LeftButtonReleaseEvent: self->LastButtonPressed = vtkImagePlaneWidget::LEFT_BUTTON; self->OnLeftButtonUp(); break; case vtkCommand::MiddleButtonPressEvent: self->LastButtonPressed = vtkImagePlaneWidget::MIDDLE_BUTTON; self->OnMiddleButtonDown(); break; case vtkCommand::MiddleButtonReleaseEvent: self->LastButtonPressed = vtkImagePlaneWidget::MIDDLE_BUTTON; self->OnMiddleButtonUp(); break; case vtkCommand::RightButtonPressEvent: self->LastButtonPressed = vtkImagePlaneWidget::RIGHT_BUTTON; self->OnRightButtonDown(); break; case vtkCommand::RightButtonReleaseEvent: self->LastButtonPressed = vtkImagePlaneWidget::RIGHT_BUTTON; self->OnRightButtonUp(); break; case vtkCommand::MouseMoveEvent: self->OnMouseMove(); break; } } void vtkImagePlaneWidget::AddObservers(void) { // listen for the following events vtkRenderWindowInteractor *i = this->Interactor; if (i) { i->AddObserver(vtkCommand::MouseMoveEvent, this->EventCallbackCommand, this->Priority); i->AddObserver(vtkCommand::LeftButtonPressEvent, this->EventCallbackCommand, this->Priority); i->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->EventCallbackCommand, this->Priority); i->AddObserver(vtkCommand::MiddleButtonPressEvent, this->EventCallbackCommand, this->Priority); i->AddObserver(vtkCommand::MiddleButtonReleaseEvent, this->EventCallbackCommand, this->Priority); i->AddObserver(vtkCommand::RightButtonPressEvent, this->EventCallbackCommand, this->Priority); i->AddObserver(vtkCommand::RightButtonReleaseEvent, this->EventCallbackCommand, this->Priority); } } void vtkImagePlaneWidget::SetInteraction(int interact) { if (this->Interactor && this->Enabled) { if (this->Interaction == interact) { return; } if (interact == 0) { this->Interactor->RemoveObserver(this->EventCallbackCommand); } else { this->AddObservers(); } this->Interaction = interact; } else { vtkGenericWarningMacro(<<"set interactor and Enabled before changing interaction..."); } } void vtkImagePlaneWidget::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if ( this->PlaneProperty ) { os << indent << "Plane Property:\n"; this->PlaneProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Plane Property: (none)\n"; } if ( this->SelectedPlaneProperty ) { os << indent << "Selected Plane Property:\n"; this->SelectedPlaneProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Selected Plane Property: (none)\n"; } if ( this->LookupTable ) { os << indent << "LookupTable:\n"; this->LookupTable->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "LookupTable: (none)\n"; } if ( this->CursorProperty ) { os << indent << "Cursor Property:\n"; this->CursorProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Cursor Property: (none)\n"; } if ( this->MarginProperty ) { os << indent << "Margin Property:\n"; this->MarginProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Margin Property: (none)\n"; } if ( this->TexturePlaneProperty ) { os << indent << "TexturePlane Property:\n"; this->TexturePlaneProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "TexturePlane Property: (none)\n"; } if ( this->ColorMap ) { os << indent << "ColorMap:\n"; this->ColorMap->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "ColorMap: (none)\n"; } double *o = this->PlaneSource->GetOrigin(); double *pt1 = this->PlaneSource->GetPoint1(); double *pt2 = this->PlaneSource->GetPoint2(); os << indent << "Origin: (" << o[0] << ", " << o[1] << ", " << o[2] << ")\n"; os << indent << "Point 1: (" << pt1[0] << ", " << pt1[1] << ", " << pt1[2] << ")\n"; os << indent << "Point 2: (" << pt2[0] << ", " << pt2[1] << ", " << pt2[2] << ")\n"; os << indent << "Current Cursor Position: (" << this->CurrentCursorPosition[0] << ", " << this->CurrentCursorPosition[1] << ", " << this->CurrentCursorPosition[2] << ")\n"; os << indent << "Current Image Value: " << this->CurrentImageValue << "\n"; os << indent << "Plane Orientation: " << this->PlaneOrientation << "\n"; os << indent << "Reslice Interpolate: " << this->ResliceInterpolate << "\n"; os << indent << "Texture Interpolate: " << (this->TextureInterpolate ? "On\n" : "Off\n") ; os << indent << "Texture Visibility: " << (this->TextureVisibility ? "On\n" : "Off\n") ; os << indent << "Restrict Plane To Volume: " << (this->RestrictPlaneToVolume ? "On\n" : "Off\n") ; os << indent << "Display Text: " << (this->DisplayText ? "On\n" : "Off\n") ; os << indent << "Interaction: " << (this->Interaction ? "On\n" : "Off\n") ; os << indent << "User Controlled Lookup Table: " << (this->UserControlledLookupTable ? "On\n" : "Off\n") ; os << indent << "LeftButtonAction: " << this->LeftButtonAction << endl; os << indent << "MiddleButtonAction: " << this->MiddleButtonAction << endl; os << indent << "RightButtonAction: " << this->RightButtonAction << endl; os << indent << "LeftButtonAutoModifier: " << this->LeftButtonAutoModifier << endl; os << indent << "MiddleButtonAutoModifier: " << this->MiddleButtonAutoModifier << endl; os << indent << "RightButtonAutoModifier: " << this->RightButtonAutoModifier << endl; os << indent << "UseContinuousCursor: " << (this->UseContinuousCursor ? "On\n" : "Off\n") ; } void vtkImagePlaneWidget::BuildRepresentation() { this->PlaneSource->Update(); double *o = this->PlaneSource->GetOrigin(); double *pt1 = this->PlaneSource->GetPoint1(); double *pt2 = this->PlaneSource->GetPoint2(); double x[3]; x[0] = o[0] + (pt1[0]-o[0]) + (pt2[0]-o[0]); x[1] = o[1] + (pt1[1]-o[1]) + (pt2[1]-o[1]); x[2] = o[2] + (pt1[2]-o[2]) + (pt2[2]-o[2]); vtkPoints* points = this->PlaneOutlinePolyData->GetPoints(); points->SetPoint(0,o); points->SetPoint(1,pt1); points->SetPoint(2,x); points->SetPoint(3,pt2); points->GetData()->Modified(); this->PlaneOutlinePolyData->Modified(); } void vtkImagePlaneWidget::HighlightPlane(int highlight) { if ( highlight ) { this->PlaneOutlineActor->SetProperty(this->SelectedPlaneProperty); this->PlanePicker->GetPickPosition(this->LastPickPosition); } else { this->PlaneOutlineActor->SetProperty(this->PlaneProperty); } } void vtkImagePlaneWidget::OnLeftButtonDown() { switch (this->LeftButtonAction) { case vtkImagePlaneWidget::CURSOR_ACTION: this->StartCursor(); break; case vtkImagePlaneWidget::SLICE_MOTION_ACTION: this->StartSliceMotion(); break; case vtkImagePlaneWidget::WINDOW_LEVEL_ACTION: this->StartWindowLevel(); break; } } void vtkImagePlaneWidget::OnLeftButtonUp() { switch (this->LeftButtonAction) { case vtkImagePlaneWidget::CURSOR_ACTION: this->StopCursor(); break; case vtkImagePlaneWidget::SLICE_MOTION_ACTION: this->StopSliceMotion(); break; case vtkImagePlaneWidget::WINDOW_LEVEL_ACTION: this->StopWindowLevel(); break; } } void vtkImagePlaneWidget::OnMiddleButtonDown() { switch (this->MiddleButtonAction) { case vtkImagePlaneWidget::CURSOR_ACTION: this->StartCursor(); break; case vtkImagePlaneWidget::SLICE_MOTION_ACTION: this->StartSliceMotion(); break; case vtkImagePlaneWidget::WINDOW_LEVEL_ACTION: this->StartWindowLevel(); break; } } void vtkImagePlaneWidget::OnMiddleButtonUp() { switch (this->MiddleButtonAction) { case vtkImagePlaneWidget::CURSOR_ACTION: this->StopCursor(); break; case vtkImagePlaneWidget::SLICE_MOTION_ACTION: this->StopSliceMotion(); break; case vtkImagePlaneWidget::WINDOW_LEVEL_ACTION: this->StopWindowLevel(); break; } } void vtkImagePlaneWidget::OnRightButtonDown() { switch (this->RightButtonAction) { case vtkImagePlaneWidget::CURSOR_ACTION: this->StartCursor(); break; case vtkImagePlaneWidget::SLICE_MOTION_ACTION: this->StartSliceMotion(); break; case vtkImagePlaneWidget::WINDOW_LEVEL_ACTION: this->StartWindowLevel(); break; } } void vtkImagePlaneWidget::OnRightButtonUp() { switch (this->RightButtonAction) { case vtkImagePlaneWidget::CURSOR_ACTION: this->StopCursor(); break; case vtkImagePlaneWidget::SLICE_MOTION_ACTION: this->StopSliceMotion(); break; case vtkImagePlaneWidget::WINDOW_LEVEL_ACTION: this->StopWindowLevel(); break; } } void vtkImagePlaneWidget::StartCursor() { int X = this->Interactor->GetEventPosition()[0]; int Y = this->Interactor->GetEventPosition()[1]; // Okay, make sure that the pick is in the current renderer if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y)) { this->State = vtkImagePlaneWidget::Outside; return; } // Okay, we can process this. If anything is picked, then we // can start pushing the plane. vtkAssemblyPath *path; this->PlanePicker->Pick(X,Y,0.0,this->CurrentRenderer); path = this->PlanePicker->GetPath(); int found = 0; int i; if ( path != 0 ) { // Deal with the possibility that we may be using a shared picker vtkCollectionSimpleIterator sit; path->InitTraversal(sit); vtkAssemblyNode *node; for ( i = 0; i < path->GetNumberOfItems() && !found ; i++ ) { node = path->GetNextNode(sit); if ( node->GetViewProp() == vtkProp::SafeDownCast(this->TexturePlaneActor) ) { found = 1; } } } if( ! found || path == 0 ) { this->State = vtkImagePlaneWidget::Outside; this->HighlightPlane(0); this->ActivateCursor(0); this->ActivateText(0); return; } else { this->State = vtkImagePlaneWidget::Cursoring; this->HighlightPlane(1); this->ActivateCursor(1); this->ActivateText(1); this->UpdateCursor(X,Y); this->ManageTextDisplay(); } this->EventCallbackCommand->SetAbortFlag(1); this->StartInteraction(); this->InvokeEvent(vtkCommand::StartInteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::StopCursor() { if ( this->State == vtkImagePlaneWidget::Outside || this->State == vtkImagePlaneWidget::Start ) { return; } this->State = vtkImagePlaneWidget::Start; this->HighlightPlane(0); this->ActivateCursor(0); this->ActivateText(0); this->EventCallbackCommand->SetAbortFlag(1); this->EndInteraction(); this->InvokeEvent(vtkCommand::EndInteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::StartSliceMotion() { int X = this->Interactor->GetEventPosition()[0]; int Y = this->Interactor->GetEventPosition()[1]; // Okay, make sure that the pick is in the current renderer if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y)) { this->State = vtkImagePlaneWidget::Outside; return; } // Okay, we can process this. If anything is picked, then we // can start pushing or check for adjusted states. vtkAssemblyPath *path; this->PlanePicker->Pick(X,Y,0.0,this->CurrentRenderer); path = this->PlanePicker->GetPath(); int found = 0; int i; if ( path != 0 ) { // Deal with the possibility that we may be using a shared picker vtkCollectionSimpleIterator sit; path->InitTraversal(sit); vtkAssemblyNode *node; for(i = 0; i< path->GetNumberOfItems() && !found ;i++) { node = path->GetNextNode(sit); if(node->GetViewProp() == vtkProp::SafeDownCast(this->TexturePlaneActor) ) { found = 1; } } } if ( !found || path == 0 ) { this->State = vtkImagePlaneWidget::Outside; this->HighlightPlane(0); this->ActivateMargins(0); return; } else { this->State = vtkImagePlaneWidget::Pushing; this->HighlightPlane(1); this->ActivateMargins(1); this->AdjustState(); this->UpdateMargins(); } this->EventCallbackCommand->SetAbortFlag(1); this->StartInteraction(); this->InvokeEvent(vtkCommand::StartInteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::StopSliceMotion() { if ( this->State == vtkImagePlaneWidget::Outside || this->State == vtkImagePlaneWidget::Start ) { return; } this->State = vtkImagePlaneWidget::Start; this->HighlightPlane(0); this->ActivateMargins(0); this->EventCallbackCommand->SetAbortFlag(1); this->EndInteraction(); this->InvokeEvent(vtkCommand::EndInteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::StartWindowLevel() { int X = this->Interactor->GetEventPosition()[0]; int Y = this->Interactor->GetEventPosition()[1]; // Okay, make sure that the pick is in the current renderer if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y)) { this->State = vtkImagePlaneWidget::Outside; return; } // Okay, we can process this. If anything is picked, then we // can start window-levelling. vtkAssemblyPath *path; this->PlanePicker->Pick(X,Y,0.0,this->CurrentRenderer); path = this->PlanePicker->GetPath(); int found = 0; int i; if ( path != 0 ) { // Deal with the possibility that we may be using a shared picker vtkCollectionSimpleIterator sit; path->InitTraversal(sit); vtkAssemblyNode *node; for ( i = 0; i < path->GetNumberOfItems() && !found ; i++ ) { node = path->GetNextNode(sit); if ( node->GetViewProp() == vtkProp::SafeDownCast(this->TexturePlaneActor) ) { found = 1; } } } if( ! found || path == 0 ) { this->State = vtkImagePlaneWidget::Outside; this->HighlightPlane(0); this->ActivateText(0); return; } else { this->State = vtkImagePlaneWidget::WindowLevelling; this->HighlightPlane(1); this->ActivateText(1); this->WindowLevel(X,Y); this->ManageTextDisplay(); } this->EventCallbackCommand->SetAbortFlag(1); this->StartInteraction(); this->InvokeEvent(vtkCommand::StartInteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::StopWindowLevel() { if ( this->State == vtkImagePlaneWidget::Outside || this->State == vtkImagePlaneWidget::Start ) { return; } this->State = vtkImagePlaneWidget::Start; this->HighlightPlane(0); this->ActivateText(0); this->EventCallbackCommand->SetAbortFlag(1); this->EndInteraction(); this->InvokeEvent(vtkCommand::EndInteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::OnMouseMove() { // See whether we're active // if ( this->State == vtkImagePlaneWidget::Outside || this->State == vtkImagePlaneWidget::Start ) { return; } int X = this->Interactor->GetEventPosition()[0]; int Y = this->Interactor->GetEventPosition()[1]; // Do different things depending on state // Calculations everybody does // double focalPoint[4], pickPoint[4], prevPickPoint[4]; double z, vpn[3]; vtkCamera *camera = this->CurrentRenderer->GetActiveCamera(); if ( ! camera ) { return; } // Compute the two points defining the motion vector // this->ComputeWorldToDisplay(this->LastPickPosition[0], this->LastPickPosition[1], this->LastPickPosition[2], focalPoint); z = focalPoint[2]; this->ComputeDisplayToWorld( double(this->Interactor->GetLastEventPosition()[0]), double(this->Interactor->GetLastEventPosition()[1]), z, prevPickPoint); this->ComputeDisplayToWorld(double(X), double(Y), z, pickPoint); if ( this->State == vtkImagePlaneWidget::WindowLevelling ) { this->WindowLevel(X,Y); this->ManageTextDisplay(); } else if ( this->State == vtkImagePlaneWidget::Pushing ) { this->Push(prevPickPoint, pickPoint); this->UpdatePlane(); this->UpdateMargins(); this->BuildRepresentation(); } else if ( this->State == vtkImagePlaneWidget::Spinning ) { this->Spin(prevPickPoint, pickPoint); this->UpdatePlane(); this->UpdateMargins(); this->BuildRepresentation(); } else if ( this->State == vtkImagePlaneWidget::Rotating ) { camera->GetViewPlaneNormal(vpn); this->Rotate(prevPickPoint, pickPoint, vpn); this->UpdatePlane(); this->UpdateMargins(); this->BuildRepresentation(); } else if ( this->State == vtkImagePlaneWidget::Scaling ) { this->Scale(prevPickPoint, pickPoint, X, Y); this->UpdatePlane(); this->UpdateMargins(); this->BuildRepresentation(); } else if ( this->State == vtkImagePlaneWidget::Moving ) { this->Translate(prevPickPoint, pickPoint); this->UpdatePlane(); this->UpdateMargins(); this->BuildRepresentation(); } else if ( this->State == vtkImagePlaneWidget::Cursoring ) { this->UpdateCursor(X,Y); this->ManageTextDisplay(); } // Interact, if desired // this->EventCallbackCommand->SetAbortFlag(1); this->InvokeEvent(vtkCommand::InteractionEvent,0); this->Interactor->Render(); } void vtkImagePlaneWidget::WindowLevel(int X, int Y) { double range[2]; this->LookupTable->GetTableRange(range); double window = range[1] - range[0]; double level = 0.5*(range[0] + range[1]); double owin = this->OriginalWindow; level = level + (X - this->Interactor->GetLastEventPosition()[0])*owin/500.0; window = window + (this->Interactor->GetLastEventPosition()[1] - Y)*owin/250.0; if ( window == 0.0 ) { window = 0.001; } double rmin = level - window*0.5; double rmax = level + window*0.5; if( rmin < rmax ) { this->CurrentWindow = window; this->CurrentLevel = level; if (!this->UserControlledLookupTable) { this->LookupTable->SetTableRange(rmin,rmax); } } } void vtkImagePlaneWidget::SetWindowLevel(double window, double level) { double rmin = level - window*0.5; double rmax = level + window*0.5; this->CurrentWindow = window; this->OriginalWindow = window; this->CurrentLevel = level; this->OriginalLevel = level; this->LookupTable->SetTableRange(rmin,rmax); if(this->Enabled) { this->Interactor->Render(); } } void vtkImagePlaneWidget::GetWindowLevel(double wl[2]) { double range[2]; this->LookupTable->GetTableRange(range); wl[0] = range[1] - range[0]; wl[1] = 0.5*(range[0]+range[1]); } int vtkImagePlaneWidget::GetCursorData(double xyzv[4]) { if ( this->State != vtkImagePlaneWidget::Cursoring || \ this->CurrentImageValue == VTK_DOUBLE_MAX ) { return 0; } xyzv[0] = this->CurrentCursorPosition[0]; xyzv[1] = this->CurrentCursorPosition[1]; xyzv[2] = this->CurrentCursorPosition[2]; xyzv[3] = this->CurrentImageValue; return 1; } int vtkImagePlaneWidget::GetCursorDataStatus() { if ( this->State != vtkImagePlaneWidget::Cursoring || \ this->CurrentImageValue == VTK_DOUBLE_MAX ) { return 0; } return 1; } void vtkImagePlaneWidget::ManageTextDisplay() { if ( !this->DisplayText ) { return; } if ( this->State == vtkImagePlaneWidget::WindowLevelling ) { sprintf(this->TextBuff,"Window, Level: ( %g, %g )", this->CurrentWindow, this->CurrentLevel ); } else if ( this->State == vtkImagePlaneWidget::Cursoring ) { if( this->CurrentImageValue == VTK_DOUBLE_MAX ) { sprintf(this->TextBuff,"Off Image"); } else { sprintf(this->TextBuff,"( %g, %g, %g ): %g", this->CurrentCursorPosition[0], this->CurrentCursorPosition[1], this->CurrentCursorPosition[2],this->CurrentImageValue); } } this->TextActor->SetInput(this->TextBuff); this->TextActor->Modified(); } void vtkImagePlaneWidget::Push(double *p1, double *p2) { // Get the motion vector // double v[3]; v[0] = p2[0] - p1[0]; v[1] = p2[1] - p1[1]; v[2] = p2[2] - p1[2]; this->PlaneSource->Push( vtkMath::Dot( v, this->PlaneSource->GetNormal() ) ); } void vtkImagePlaneWidget::CreateDefaultProperties() { if ( ! this->PlaneProperty ) { this->PlaneProperty = vtkProperty::New(); this->PlaneProperty->SetAmbient(1); this->PlaneProperty->SetColor(1,1,1); this->PlaneProperty->SetRepresentationToWireframe(); this->PlaneProperty->SetInterpolationToFlat(); } if ( ! this->SelectedPlaneProperty ) { this->SelectedPlaneProperty = vtkProperty::New(); this->SelectedPlaneProperty->SetAmbient(1); this->SelectedPlaneProperty->SetColor(0,1,0); this->SelectedPlaneProperty->SetRepresentationToWireframe(); this->SelectedPlaneProperty->SetInterpolationToFlat(); } if ( ! this->CursorProperty ) { this->CursorProperty = vtkProperty::New(); this->CursorProperty->SetAmbient(1); this->CursorProperty->SetColor(1,0,0); this->CursorProperty->SetRepresentationToWireframe(); this->CursorProperty->SetInterpolationToFlat(); } if ( ! this->MarginProperty ) { this->MarginProperty = vtkProperty::New(); this->MarginProperty->SetAmbient(1); this->MarginProperty->SetColor(0,0,1); this->MarginProperty->SetRepresentationToWireframe(); this->MarginProperty->SetInterpolationToFlat(); } if ( ! this->TexturePlaneProperty ) { this->TexturePlaneProperty = vtkProperty::New(); this->TexturePlaneProperty->SetAmbient(1); this->TexturePlaneProperty->SetInterpolationToFlat(); } } void vtkImagePlaneWidget::PlaceWidget(double bds[6]) { double bounds[6], center[3]; this->AdjustBounds(bds, bounds, center); if ( this->PlaneOrientation == 1 ) { this->PlaneSource->SetOrigin(bounds[0],center[1],bounds[4]); this->PlaneSource->SetPoint1(bounds[1],center[1],bounds[4]); this->PlaneSource->SetPoint2(bounds[0],center[1],bounds[5]); } else if ( this->PlaneOrientation == 2 ) { this->PlaneSource->SetOrigin(bounds[0],bounds[2],center[2]); this->PlaneSource->SetPoint1(bounds[1],bounds[2],center[2]); this->PlaneSource->SetPoint2(bounds[0],bounds[3],center[2]); } else //default or x-normal { this->PlaneSource->SetOrigin(center[0],bounds[2],bounds[4]); this->PlaneSource->SetPoint1(center[0],bounds[3],bounds[4]); this->PlaneSource->SetPoint2(center[0],bounds[2],bounds[5]); } this->UpdatePlane(); this->BuildRepresentation(); } void vtkImagePlaneWidget::SetPlaneOrientation(int i) { // Generate a XY plane if i = 2, z-normal // or a YZ plane if i = 0, x-normal // or a ZX plane if i = 1, y-normal // this->PlaneOrientation = i; // This method must be called _after_ SetInput // this->ImageData = vtkImageData::SafeDownCast(this->Reslice->GetInput()); if ( !this->ImageData ) { vtkErrorMacro(<<"SetInput() before setting plane orientation."); return; } this->ImageData->UpdateInformation(); int extent[6]; this->ImageData->GetWholeExtent(extent); double origin[3]; this->ImageData->GetOrigin(origin); double spacing[3]; this->ImageData->GetSpacing(spacing); // Prevent obscuring voxels by offsetting the plane geometry // double xbounds[] = {origin[0] + spacing[0] * (extent[0] - 0.5), origin[0] + spacing[0] * (extent[1] + 0.5)}; double ybounds[] = {origin[1] + spacing[1] * (extent[2] - 0.5), origin[1] + spacing[1] * (extent[3] + 0.5)}; double zbounds[] = {origin[2] + spacing[2] * (extent[4] - 0.5), origin[2] + spacing[2] * (extent[5] + 0.5)}; if ( spacing[0] < 0.0 ) { double t = xbounds[0]; xbounds[0] = xbounds[1]; xbounds[1] = t; } if ( spacing[1] < 0.0 ) { double t = ybounds[0]; ybounds[0] = ybounds[1]; ybounds[1] = t; } if ( spacing[2] < 0.0 ) { double t = zbounds[0]; zbounds[0] = zbounds[1]; zbounds[1] = t; } if ( i == 2 ) //XY, z-normal { this->PlaneSource->SetOrigin(xbounds[0],ybounds[0],zbounds[0]); this->PlaneSource->SetPoint1(xbounds[1],ybounds[0],zbounds[0]); this->PlaneSource->SetPoint2(xbounds[0],ybounds[1],zbounds[0]); } else if ( i == 0 ) //YZ, x-normal { this->PlaneSource->SetOrigin(xbounds[0],ybounds[0],zbounds[0]); this->PlaneSource->SetPoint1(xbounds[0],ybounds[1],zbounds[0]); this->PlaneSource->SetPoint2(xbounds[0],ybounds[0],zbounds[1]); } else //ZX, y-normal { this->PlaneSource->SetOrigin(xbounds[0],ybounds[0],zbounds[0]); this->PlaneSource->SetPoint1(xbounds[0],ybounds[0],zbounds[1]); this->PlaneSource->SetPoint2(xbounds[1],ybounds[0],zbounds[0]); } this->UpdatePlane(); this->BuildRepresentation(); this->Modified(); } void vtkImagePlaneWidget::SetInput(vtkDataSet* input) { this->Superclass::SetInput(input); this->ImageData = vtkImageData::SafeDownCast(this->GetInput()); if( !this->ImageData ) { // If NULL is passed, remove any reference that Reslice had // on the old ImageData // this->Reslice->SetInput(NULL); return; } double range[2]; this->ImageData->GetScalarRange(range); if ( !this->UserControlledLookupTable ) { this->LookupTable->SetTableRange(range[0],range[1]); this->LookupTable->Build(); } this->OriginalWindow = range[1] - range[0]; this->OriginalLevel = 0.5*(range[0] + range[1]); this->Reslice->SetInput(this->ImageData); int interpolate = this->ResliceInterpolate; this->ResliceInterpolate = -1; // Force change this->SetResliceInterpolate(interpolate); this->ColorMap->SetInput(this->Reslice->GetOutput()); this->Texture->SetInput(this->ColorMap->GetOutput()); this->Texture->SetInterpolate(this->TextureInterpolate); this->SetPlaneOrientation(this->PlaneOrientation); } void vtkImagePlaneWidget::UpdatePlane() { if ( !this->Reslice || \ !(this->ImageData = vtkImageData::SafeDownCast(this->Reslice->GetInput())) ) { return; } // Calculate appropriate pixel spacing for the reslicing // this->ImageData->UpdateInformation(); double spacing[3]; this->ImageData->GetSpacing(spacing); int i; if ( this->RestrictPlaneToVolume ) { double origin[3]; this->ImageData->GetOrigin(origin); int extent[6]; this->ImageData->GetWholeExtent(extent); double bounds[] = {origin[0] + spacing[0]*extent[0], //xmin origin[0] + spacing[0]*extent[1], //xmax origin[1] + spacing[1]*extent[2], //ymin origin[1] + spacing[1]*extent[3], //ymax origin[2] + spacing[2]*extent[4], //zmin origin[2] + spacing[2]*extent[5]};//zmax for ( i = 0; i <= 4; i += 2 ) // reverse bounds if necessary { if ( bounds[i] > bounds[i+1] ) { double t = bounds[i+1]; bounds[i+1] = bounds[i]; bounds[i] = t; } } double abs_normal[3]; this->PlaneSource->GetNormal(abs_normal); double planeCenter[3]; this->PlaneSource->GetCenter(planeCenter); double nmax = 0.0; int k = 0; for ( i = 0; i < 3; i++ ) { abs_normal[i] = fabs(abs_normal[i]); if ( abs_normal[i]>nmax ) { nmax = abs_normal[i]; k = i; } } // Force the plane to lie within the true image bounds along its normal // if ( planeCenter[k] > bounds[2*k+1] ) { planeCenter[k] = bounds[2*k+1]; } else if ( planeCenter[k] < bounds[2*k] ) { planeCenter[k] = bounds[2*k]; } this->PlaneSource->SetCenter(planeCenter); } double planeAxis1[3]; double planeAxis2[3]; this->GetVector1(planeAxis1); this->GetVector2(planeAxis2); // The x,y dimensions of the plane // double planeSizeX = vtkMath::Normalize(planeAxis1); double planeSizeY = vtkMath::Normalize(planeAxis2); double normal[3]; this->PlaneSource->GetNormal(normal); // Generate the slicing matrix // this->ResliceAxes->Identity(); for ( i = 0; i < 3; i++ ) { this->ResliceAxes->SetElement(0,i,planeAxis1[i]); this->ResliceAxes->SetElement(1,i,planeAxis2[i]); this->ResliceAxes->SetElement(2,i,normal[i]); } double planeOrigin[4]; this->PlaneSource->GetOrigin(planeOrigin); planeOrigin[3] = 1.0; double originXYZW[4]; this->ResliceAxes->MultiplyPoint(planeOrigin, originXYZW); this->ResliceAxes->Transpose(); double neworiginXYZW[4]; this->ResliceAxes->MultiplyPoint(originXYZW, neworiginXYZW); this->ResliceAxes->SetElement(0,3,neworiginXYZW[0]); this->ResliceAxes->SetElement(1,3,neworiginXYZW[1]); this->ResliceAxes->SetElement(2,3,neworiginXYZW[2]); this->Reslice->SetResliceAxes(this->ResliceAxes); double spacingX = fabs(planeAxis1[0]*spacing[0])+\ fabs(planeAxis1[1]*spacing[1])+\ fabs(planeAxis1[2]*spacing[2]); double spacingY = fabs(planeAxis2[0]*spacing[0])+\ fabs(planeAxis2[1]*spacing[1])+\ fabs(planeAxis2[2]*spacing[2]); // Pad extent up to a power of two for efficient texture mapping // make sure we're working with valid values double realExtentX = ( spacingX == 0 ) ? 0 : planeSizeX / spacingX; int extentX; // Sanity check the input data: // * if realExtentX is too large, extentX will wrap // * if spacingX is 0, things will blow up. // * if realExtentX is naturally 0 or < 0, the padding will yield an // extentX of 1, which is also not desirable if the input data is invalid. if (realExtentX > (VTK_INT_MAX >> 1) || realExtentX < 1) { vtkErrorMacro(<<"Invalid X extent. Perhaps the input data is empty?"); extentX = 0; } else { extentX = 1; while (extentX < realExtentX) { extentX = extentX << 1; } } // make sure extentY doesn't wrap during padding double realExtentY = ( spacingY == 0 ) ? 0 : planeSizeY / spacingY; int extentY; if (realExtentY > (VTK_INT_MAX >> 1) || realExtentY < 1) { vtkErrorMacro(<<"Invalid Y extent. Perhaps the input data is empty?"); extentY = 0; } else { extentY = 1; while (extentY < realExtentY) { extentY = extentY << 1; } } double outputSpacingX = planeSizeX/extentX; double outputSpacingY = planeSizeY/extentY; this->Reslice->SetOutputSpacing(outputSpacingX, outputSpacingY, 1); this->Reslice->SetOutputOrigin(0.5*outputSpacingX, 0.5*outputSpacingY, 0); this->Reslice->SetOutputExtent(0, extentX-1, 0, extentY-1, 0, 0); } vtkImageData* vtkImagePlaneWidget::GetResliceOutput() { if ( ! this->Reslice ) { return 0; } return this->Reslice->GetOutput(); } void vtkImagePlaneWidget::SetResliceInterpolate(int i) { if ( this->ResliceInterpolate == i ) { return; } this->ResliceInterpolate = i; this->Modified(); if ( !this->Reslice ) { return; } if ( i == VTK_NEAREST_RESLICE ) { this->Reslice->SetInterpolationModeToNearestNeighbor(); } else if ( i == VTK_LINEAR_RESLICE) { this->Reslice->SetInterpolationModeToLinear(); } else { this->Reslice->SetInterpolationModeToCubic(); } this->Texture->SetInterpolate(this->TextureInterpolate); } void vtkImagePlaneWidget::SetPicker(vtkCellPicker* picker) { if (this->PlanePicker != picker) { // to avoid destructor recursion vtkCellPicker *temp = this->PlanePicker; this->PlanePicker = picker; if (temp != 0) { temp->UnRegister(this); } if (this->PlanePicker != 0) { this->PlanePicker->Register(this); this->PlanePicker->SetTolerance(0.005); //need some fluff this->PlanePicker->AddPickList(this->TexturePlaneActor); this->PlanePicker->PickFromListOn(); } } } vtkLookupTable* vtkImagePlaneWidget::CreateDefaultLookupTable() { vtkLookupTable* lut = vtkLookupTable::New(); lut->Register(this); lut->Delete(); lut->SetNumberOfColors( 256); lut->SetHueRange( 0, 0); lut->SetSaturationRange( 0, 0); lut->SetValueRange( 0 ,1); lut->SetAlphaRange( 1, 1); lut->Build(); return lut; } void vtkImagePlaneWidget::SetLookupTable(vtkLookupTable* table) { if (this->LookupTable != table) { // to avoid destructor recursion vtkLookupTable *temp = this->LookupTable; this->LookupTable = table; if (temp != 0) { temp->UnRegister(this); } if (this->LookupTable != 0) { this->LookupTable->Register(this); } else //create a default lut { this->LookupTable = this->CreateDefaultLookupTable(); } } this->ColorMap->SetLookupTable(this->LookupTable); this->Texture->SetLookupTable(this->LookupTable); if( this->ImageData && !this->UserControlledLookupTable) { double range[2]; this->ImageData->GetScalarRange(range); this->LookupTable->SetTableRange(range[0],range[1]); this->LookupTable->Build(); this->OriginalWindow = range[1] - range[0]; this->OriginalLevel = 0.5*(range[0] + range[1]); } } void vtkImagePlaneWidget::SetSlicePosition(double position) { double amount = 0.0; double planeOrigin[3]; this->PlaneSource->GetOrigin( planeOrigin ); if ( this->PlaneOrientation == 2 ) // z axis { amount = position - planeOrigin[2]; } else if ( this->PlaneOrientation == 0 ) // x axis { amount = position - planeOrigin[0]; } else if ( this->PlaneOrientation == 1 ) //y axis { amount = position - planeOrigin[1]; } else { vtkGenericWarningMacro("only works for ortho planes: set plane orientation first"); return; } this->PlaneSource->Push( amount ); this->UpdatePlane(); this->BuildRepresentation(); this->Modified(); } double vtkImagePlaneWidget::GetSlicePosition() { double planeOrigin[3]; this->PlaneSource->GetOrigin( planeOrigin); if ( this->PlaneOrientation == 2 ) { return planeOrigin[2]; } else if ( this->PlaneOrientation == 1 ) { return planeOrigin[1]; } else if ( this->PlaneOrientation == 0 ) { return planeOrigin[0]; } else { vtkGenericWarningMacro("only works for ortho planes: set plane orientation first"); } return 0.0; } void vtkImagePlaneWidget::SetSliceIndex(int index) { if ( !this->Reslice ) { return; } this->ImageData = vtkImageData::SafeDownCast(this->Reslice->GetInput()); if ( !this->ImageData ) { return; } this->ImageData->UpdateInformation(); double origin[3]; this->ImageData->GetOrigin(origin); double spacing[3]; this->ImageData->GetSpacing(spacing); double planeOrigin[3]; this->PlaneSource->GetOrigin(planeOrigin); double pt1[3]; this->PlaneSource->GetPoint1(pt1); double pt2[3]; this->PlaneSource->GetPoint2(pt2); if ( this->PlaneOrientation == 2 ) { planeOrigin[2] = origin[2] + index*spacing[2]; pt1[2] = planeOrigin[2]; pt2[2] = planeOrigin[2]; } else if ( this->PlaneOrientation == 1 ) { planeOrigin[1] = origin[1] + index*spacing[1]; pt1[1] = planeOrigin[1]; pt2[1] = planeOrigin[1]; } else if ( this->PlaneOrientation == 0 ) { planeOrigin[0] = origin[0] + index*spacing[0]; pt1[0] = planeOrigin[0]; pt2[0] = planeOrigin[0]; } else { vtkGenericWarningMacro("only works for ortho planes: set plane orientation first"); return; } this->PlaneSource->SetOrigin(planeOrigin); this->PlaneSource->SetPoint1(pt1); this->PlaneSource->SetPoint2(pt2); this->UpdatePlane(); this->BuildRepresentation(); this->Modified(); } int vtkImagePlaneWidget::GetSliceIndex() { if ( ! this->Reslice ) { return 0; } this->ImageData = vtkImageData::SafeDownCast(this->Reslice->GetInput()); if ( ! this->ImageData ) { return 0; } this->ImageData->UpdateInformation(); double origin[3]; this->ImageData->GetOrigin(origin); double spacing[3]; this->ImageData->GetSpacing(spacing); double planeOrigin[3]; this->PlaneSource->GetOrigin(planeOrigin); if ( this->PlaneOrientation == 2 ) { return vtkMath::Round((planeOrigin[2]-origin[2])/spacing[2]); } else if ( this->PlaneOrientation == 1 ) { return vtkMath::Round((planeOrigin[1]-origin[1])/spacing[1]); } else if ( this->PlaneOrientation == 0 ) { return vtkMath::Round((planeOrigin[0]-origin[0])/spacing[0]); } else { vtkGenericWarningMacro("only works for ortho planes: set plane orientation first"); } return 0; } void vtkImagePlaneWidget::ActivateCursor(int i) { if( !this->CurrentRenderer ) { return; } if( i == 0 ) { this->CursorActor->VisibilityOff(); } else { this->CursorActor->VisibilityOn(); } } void vtkImagePlaneWidget::ActivateMargins(int i) { if( !this->CurrentRenderer ) { return; } if( i == 0 ) { this->MarginActor->VisibilityOff(); } else { this->MarginActor->VisibilityOn(); } } void vtkImagePlaneWidget::ActivateText(int i) { if( !this->CurrentRenderer || !this->DisplayText) { return; } if( i == 0 ) { this->TextActor->VisibilityOff(); } else { this->TextActor->VisibilityOn(); } } void vtkImagePlaneWidget::UpdateCursor(int X, int Y ) { this->ImageData = vtkImageData::SafeDownCast(this->Reslice->GetInput()); if ( !this->ImageData ) { return; } // We're going to be extracting values with GetScalarComponentAsDouble(), // we might as well make sure that the data is there. If the data is // up to date already, this call doesn't cost very much. If we don't make // this call and the data is not up to date, the GetScalar... call will // cause a segfault. this->ImageData->Update(); vtkAssemblyPath *path; this->PlanePicker->Pick(X,Y,0.0,this->CurrentRenderer); path = this->PlanePicker->GetPath(); this->CurrentImageValue = VTK_DOUBLE_MAX; int found = 0; int i; if ( path ) { // Deal with the possibility that we may be using a shared picker vtkCollectionSimpleIterator sit; path->InitTraversal(sit); vtkAssemblyNode *node; for ( i = 0; i< path->GetNumberOfItems() && !found ; i++ ) { node = path->GetNextNode(sit); if ( node->GetViewProp() == vtkProp::SafeDownCast(this->TexturePlaneActor) ) { found = 1; } } } if( !found || path == 0 ) { this->CursorActor->VisibilityOff(); return; } else { this->CursorActor->VisibilityOn(); } double q[3]; this->PlanePicker->GetPickPosition(q); if(this->UseContinuousCursor) { found = this->UpdateContinuousCursor(q); } else { found = this->UpdateDiscreteCursor(q); } if(!found) { this->CursorActor->VisibilityOff(); return; } double o[3]; this->PlaneSource->GetOrigin(o); // q relative to the plane origin // double qro[3]; qro[0]= q[0] - o[0]; qro[1]= q[1] - o[1]; qro[2]= q[2] - o[2]; double p1o[3]; double p2o[3]; this->GetVector1(p1o); this->GetVector2(p2o); double Lp1 = vtkMath::Dot(qro,p1o)/vtkMath::Dot(p1o,p1o); double Lp2 = vtkMath::Dot(qro,p2o)/vtkMath::Dot(p2o,p2o); double p1[3]; this->PlaneSource->GetPoint1(p1); double p2[3]; this->PlaneSource->GetPoint2(p2); double a[3]; double b[3]; double c[3]; double d[3]; for (i = 0; i < 3; i++) { a[i] = o[i] + Lp2*p2o[i]; // left b[i] = p1[i] + Lp2*p2o[i]; // right c[i] = o[i] + Lp1*p1o[i]; // bottom d[i] = p2[i] + Lp1*p1o[i]; // top } vtkPoints* cursorPts = this->CursorPolyData->GetPoints(); cursorPts->SetPoint(0,a); cursorPts->SetPoint(1,b); cursorPts->SetPoint(2,c); cursorPts->SetPoint(3,d); this->CursorPolyData->Modified(); } int vtkImagePlaneWidget::UpdateContinuousCursor(double *q) { double tol2; vtkCell *cell; vtkPointData *pd; int subId; double pcoords[3], weights[8]; this->CurrentCursorPosition[0] = q[0]; this->CurrentCursorPosition[1] = q[1]; this->CurrentCursorPosition[2] = q[2]; pd = this->ImageData->GetPointData(); vtkPointData* outPD = vtkPointData::New(); outPD->InterpolateAllocate(pd, 1, 1); // Use tolerance as a function of size of source data // tol2 = this->ImageData->GetLength(); tol2 = tol2 ? tol2*tol2 / 1000.0 : 0.001; // Find the cell that contains q and get it // cell = this->ImageData->FindAndGetCell(q,NULL,-1,tol2,subId,pcoords,weights); int found = 0; if (cell) { // Interpolate the point data // outPD->InterpolatePoint(pd,0,cell->PointIds,weights); this->CurrentImageValue = outPD->GetScalars()->GetTuple1(0); found = 1; } outPD->Delete(); return found; } int vtkImagePlaneWidget::UpdateDiscreteCursor(double *q) { // vtkImageData will find the nearest implicit point to q // vtkIdType ptId = this->ImageData->FindPoint(q); if ( ptId == -1 ) { return 0; } double closestPt[3]; this->ImageData->GetPoint(ptId,closestPt); double origin[3]; this->ImageData->GetOrigin(origin); double spacing[3]; this->ImageData->GetSpacing(spacing); int extent[6]; this->ImageData->GetExtent(extent); int iq[3]; int iqtemp; for (int i = 0; i < 3; i++) { // compute world to image coords iqtemp = vtkMath::Round((closestPt[i]-origin[i])/spacing[i]); // we have a valid pick already, just enforce bounds check iq[i] = (iqtemp < extent[2*i])?extent[2*i]:((iqtemp > extent[2*i+1])?extent[2*i+1]:iqtemp); // compute image to world coords q[i] = iq[i]*spacing[i] + origin[i]; this->CurrentCursorPosition[i] = iq[i]; } this->CurrentImageValue = this->ImageData->GetScalarComponentAsDouble( \ static_cast(this->CurrentCursorPosition[0]), static_cast(this->CurrentCursorPosition[1]), static_cast(this->CurrentCursorPosition[2]),0); return 1; } void vtkImagePlaneWidget::SetOrigin(double x, double y, double z) { this->PlaneSource->SetOrigin(x,y,z); this->Modified(); } void vtkImagePlaneWidget::SetOrigin(double xyz[3]) { this->PlaneSource->SetOrigin(xyz); this->Modified(); } double* vtkImagePlaneWidget::GetOrigin() { return this->PlaneSource->GetOrigin(); } void vtkImagePlaneWidget::GetOrigin(double xyz[3]) { this->PlaneSource->GetOrigin(xyz); } void vtkImagePlaneWidget::SetPoint1(double x, double y, double z) { this->PlaneSource->SetPoint1(x,y,z); this->Modified(); } void vtkImagePlaneWidget::SetPoint1(double xyz[3]) { this->PlaneSource->SetPoint1(xyz); this->Modified(); } double* vtkImagePlaneWidget::GetPoint1() { return this->PlaneSource->GetPoint1(); } void vtkImagePlaneWidget::GetPoint1(double xyz[3]) { this->PlaneSource->GetPoint1(xyz); } void vtkImagePlaneWidget::SetPoint2(double x, double y, double z) { this->PlaneSource->SetPoint2(x,y,z); this->Modified(); } void vtkImagePlaneWidget::SetPoint2(double xyz[3]) { this->PlaneSource->SetPoint2(xyz); this->Modified(); } double* vtkImagePlaneWidget::GetPoint2() { return this->PlaneSource->GetPoint2(); } void vtkImagePlaneWidget::GetPoint2(double xyz[3]) { this->PlaneSource->GetPoint2(xyz); } double* vtkImagePlaneWidget::GetCenter() { return this->PlaneSource->GetCenter(); } void vtkImagePlaneWidget::GetCenter(double xyz[3]) { this->PlaneSource->GetCenter(xyz); } double* vtkImagePlaneWidget::GetNormal() { return this->PlaneSource->GetNormal(); } void vtkImagePlaneWidget::GetNormal(double xyz[3]) { this->PlaneSource->GetNormal(xyz); } void vtkImagePlaneWidget::GetPolyData(vtkPolyData *pd) { pd->ShallowCopy(this->PlaneSource->GetOutput()); } vtkPolyDataAlgorithm *vtkImagePlaneWidget::GetPolyDataAlgorithm() { return this->PlaneSource; } void vtkImagePlaneWidget::UpdatePlacement(void) { this->UpdatePlane(); this->UpdateMargins(); this->BuildRepresentation(); } void vtkImagePlaneWidget::SetTextProperty(vtkTextProperty* tprop) { this->TextActor->SetTextProperty(tprop); } vtkTextProperty* vtkImagePlaneWidget::GetTextProperty() { return this->TextActor->GetTextProperty(); } vtkTexture* vtkImagePlaneWidget::GetTexture() { return this->Texture; } void vtkImagePlaneWidget::GetVector1(double v1[3]) { double* p1 = this->PlaneSource->GetPoint1(); double* o = this->PlaneSource->GetOrigin(); v1[0] = p1[0] - o[0]; v1[1] = p1[1] - o[1]; v1[2] = p1[2] - o[2]; } void vtkImagePlaneWidget::GetVector2(double v2[3]) { double* p2 = this->PlaneSource->GetPoint2(); double* o = this->PlaneSource->GetOrigin(); v2[0] = p2[0] - o[0]; v2[1] = p2[1] - o[1]; v2[2] = p2[2] - o[2]; } void vtkImagePlaneWidget::AdjustState() { int *auto_modifier = NULL; switch (this->LastButtonPressed) { case vtkImagePlaneWidget::LEFT_BUTTON: auto_modifier = &this->LeftButtonAutoModifier; break; case vtkImagePlaneWidget::MIDDLE_BUTTON: auto_modifier = &this->MiddleButtonAutoModifier; break; case vtkImagePlaneWidget::RIGHT_BUTTON: auto_modifier = &this->RightButtonAutoModifier; break; } if (this->Interactor->GetShiftKey() || (auto_modifier && (*auto_modifier & vtkImagePlaneWidget::SHIFT_MODIFIER))) { this->State = vtkImagePlaneWidget::Scaling; return; } double v1[3]; this->GetVector1(v1); double v2[3]; this->GetVector2(v2); double planeSize1 = vtkMath::Normalize(v1); double planeSize2 = vtkMath::Normalize(v2); double* planeOrigin = this->PlaneSource->GetOrigin(); double ppo[3] = {this->LastPickPosition[0] - planeOrigin[0], this->LastPickPosition[1] - planeOrigin[1], this->LastPickPosition[2] - planeOrigin[2] }; double x2D = vtkMath::Dot(ppo,v1); double y2D = vtkMath::Dot(ppo,v2); // Divide plane into three zones for different user interactions: // four corners -- spin around the plane's normal at its center // four edges -- rotate around one of the plane's axes at its center // center area -- push // double marginX = planeSize1 * 0.05; double marginY = planeSize2 * 0.05; double x0 = marginX; double y0 = marginY; double x1 = planeSize1 - marginX; double y1 = planeSize2 - marginY; if ( x2D < x0 ) // left margin { if (y2D < y0) // bottom left corner { this->MarginSelectMode = 0; } else if (y2D > y1) // top left corner { this->MarginSelectMode = 3; } else // left edge { this->MarginSelectMode = 4; } } else if ( x2D > x1 ) // right margin { if (y2D < y0) // bottom right corner { this->MarginSelectMode = 1; } else if (y2D > y1) // top right corner { this->MarginSelectMode = 2; } else // right edge { this->MarginSelectMode = 5; } } else // middle { if (y2D < y0) // bottom edge { this->MarginSelectMode = 6; } else if (y2D > y1) // top edge { this->MarginSelectMode = 7; } else // central area { this->MarginSelectMode = 8; } } if (this->Interactor->GetControlKey() || (auto_modifier && (*auto_modifier & vtkImagePlaneWidget::CONTROL_MODIFIER))) { this->State = vtkImagePlaneWidget::Moving; } else { if (this->MarginSelectMode >= 0 && this->MarginSelectMode < 4) { this->State = vtkImagePlaneWidget::Spinning; return; } else if (this->MarginSelectMode == 8) { this->State = vtkImagePlaneWidget::Pushing; return; } else { this->State = vtkImagePlaneWidget::Rotating; } } double *raPtr = 0; double *rvPtr = 0; double rvfac = 1.0; double rafac = 1.0; switch ( this->MarginSelectMode ) { // left bottom corner case 0: raPtr = v2; rvPtr = v1; rvfac = -1.0; rafac = -1.0; break; // right bottom corner case 1: raPtr = v2; rvPtr = v1; rafac = -1.0; break; // right top corner case 2: raPtr = v2; rvPtr = v1; break; // left top corner case 3: raPtr = v2; rvPtr = v1; rvfac = -1.0; break; case 4: raPtr = v2; rvPtr = v1; rvfac = -1.0; break; // left case 5: raPtr = v2; rvPtr = v1; break; // right case 6: raPtr = v1; rvPtr = v2; rvfac = -1.0; break; // bottom case 7: raPtr = v1; rvPtr = v2; break; // top default: raPtr = v1; rvPtr = v2; break; } for (int i = 0; i < 3; i++) { this->RotateAxis[i] = *raPtr++ * rafac; this->RadiusVector[i] = *rvPtr++ * rvfac; } } void vtkImagePlaneWidget::Spin(double *p1, double *p2) { // Disable cursor snap // this->PlaneOrientation = 3; // Get the motion vector, in world coords // double v[3]; v[0] = p2[0] - p1[0]; v[1] = p2[1] - p1[1]; v[2] = p2[2] - p1[2]; // Plane center and normal before transform // double* wc = this->PlaneSource->GetCenter(); double* wn = this->PlaneSource->GetNormal(); // Radius vector from center to cursor position // double rv[3] = {p2[0]-wc[0], p2[1]-wc[1], p2[2]-wc[2]}; // Distance between center and cursor location // double rs = vtkMath::Normalize(rv); // Spin direction // double wn_cross_rv[3]; vtkMath::Cross(wn,rv,wn_cross_rv); // Spin angle // double dw = vtkMath::RadiansToDegrees() * vtkMath::Dot(v,wn_cross_rv) / rs; this->Transform->Identity(); this->Transform->Translate(wc[0],wc[1],wc[2]); this->Transform->RotateWXYZ(dw,wn); this->Transform->Translate(-wc[0],-wc[1],-wc[2]); double newpt[3]; this->Transform->TransformPoint(this->PlaneSource->GetPoint1(),newpt); this->PlaneSource->SetPoint1(newpt); this->Transform->TransformPoint(this->PlaneSource->GetPoint2(),newpt); this->PlaneSource->SetPoint2(newpt); this->Transform->TransformPoint(this->PlaneSource->GetOrigin(),newpt); this->PlaneSource->SetOrigin(newpt); } void vtkImagePlaneWidget::Rotate(double *p1, double *p2, double *vpn) { // Disable cursor snap // this->PlaneOrientation = 3; // Get the motion vector, in world coords // double v[3]; v[0] = p2[0] - p1[0]; v[1] = p2[1] - p1[1]; v[2] = p2[2] - p1[2]; // Plane center and normal // double* wc = this->PlaneSource->GetCenter(); // Radius of the rotating circle of the picked point // double radius = fabs( this->RadiusVector[0]*(p2[0]-wc[0]) + this->RadiusVector[1]*(p2[1]-wc[1]) + this->RadiusVector[2]*(p2[2]-wc[2]) ); // Rotate direction ra_cross_rv // double rd[3]; vtkMath::Cross(this->RotateAxis,this->RadiusVector,rd); // Direction cosin between rotating direction and view normal // double rd_dot_vpn = rd[0]*vpn[0] + rd[1]*vpn[1] + rd[2]*vpn[2]; // 'push' plane edge when mouse moves away from plane center // 'pull' plane edge when mouse moves toward plane center // double dw = vtkMath::RadiansToDegrees() * (vtkMath::Dot(this->RadiusVector,v))/radius * (-rd_dot_vpn); this->Transform->Identity(); this->Transform->Translate(wc[0],wc[1],wc[2]); this->Transform->RotateWXYZ(dw,this->RotateAxis); this->Transform->Translate(-wc[0],-wc[1],-wc[2]); double newpt[3]; this->Transform->TransformPoint(this->PlaneSource->GetPoint1(),newpt); this->PlaneSource->SetPoint1(newpt); this->Transform->TransformPoint(this->PlaneSource->GetPoint2(),newpt); this->PlaneSource->SetPoint2(newpt); this->Transform->TransformPoint(this->PlaneSource->GetOrigin(),newpt); this->PlaneSource->SetOrigin(newpt); } void vtkImagePlaneWidget::GeneratePlaneOutline() { vtkPoints* points = vtkPoints::New(VTK_DOUBLE); points->SetNumberOfPoints(4); int i; for (i = 0; i < 4; i++) { points->SetPoint(i,0.0,0.0,0.0); } vtkCellArray *cells = vtkCellArray::New(); cells->Allocate(cells->EstimateSize(4,2)); vtkIdType pts[2]; pts[0] = 3; pts[1] = 2; // top edge cells->InsertNextCell(2,pts); pts[0] = 0; pts[1] = 1; // bottom edge cells->InsertNextCell(2,pts); pts[0] = 0; pts[1] = 3; // left edge cells->InsertNextCell(2,pts); pts[0] = 1; pts[1] = 2; // right edge cells->InsertNextCell(2,pts); this->PlaneOutlinePolyData->SetPoints(points); points->Delete(); this->PlaneOutlinePolyData->SetLines(cells); cells->Delete(); vtkPolyDataMapper* planeOutlineMapper = vtkPolyDataMapper::New(); planeOutlineMapper->SetInput( this->PlaneOutlinePolyData ); planeOutlineMapper->SetResolveCoincidentTopologyToPolygonOffset(); this->PlaneOutlineActor->SetMapper(planeOutlineMapper); this->PlaneOutlineActor->PickableOff(); planeOutlineMapper->Delete(); } void vtkImagePlaneWidget::GenerateTexturePlane() { this->SetResliceInterpolate(this->ResliceInterpolate); this->LookupTable = this->CreateDefaultLookupTable(); this->ColorMap->SetLookupTable(this->LookupTable); this->ColorMap->SetOutputFormatToRGBA(); this->ColorMap->PassAlphaToOutputOn(); vtkPolyDataMapper* texturePlaneMapper = vtkPolyDataMapper::New(); texturePlaneMapper->SetInput( vtkPolyData::SafeDownCast(this->PlaneSource->GetOutput())); this->Texture->SetQualityTo32Bit(); this->Texture->MapColorScalarsThroughLookupTableOff(); this->Texture->SetInterpolate(this->TextureInterpolate); this->Texture->RepeatOff(); this->Texture->SetLookupTable(this->LookupTable); this->TexturePlaneActor->SetMapper(texturePlaneMapper); this->TexturePlaneActor->SetTexture(this->Texture); this->TexturePlaneActor->PickableOn(); texturePlaneMapper->Delete(); } void vtkImagePlaneWidget::GenerateMargins() { // Construct initial points vtkPoints* points = vtkPoints::New(VTK_DOUBLE); points->SetNumberOfPoints(8); int i; for (i = 0; i < 8; i++) { points->SetPoint(i,0.0,0.0,0.0); } vtkCellArray *cells = vtkCellArray::New(); cells->Allocate(cells->EstimateSize(4,2)); vtkIdType pts[2]; pts[0] = 0; pts[1] = 1; // top margin cells->InsertNextCell(2,pts); pts[0] = 2; pts[1] = 3; // bottom margin cells->InsertNextCell(2,pts); pts[0] = 4; pts[1] = 5; // left margin cells->InsertNextCell(2,pts); pts[0] = 6; pts[1] = 7; // right margin cells->InsertNextCell(2,pts); this->MarginPolyData->SetPoints(points); points->Delete(); this->MarginPolyData->SetLines(cells); cells->Delete(); vtkPolyDataMapper* marginMapper = vtkPolyDataMapper::New(); marginMapper->SetInput(this->MarginPolyData); marginMapper->SetResolveCoincidentTopologyToPolygonOffset(); this->MarginActor->SetMapper(marginMapper); this->MarginActor->PickableOff(); this->MarginActor->VisibilityOff(); marginMapper->Delete(); } void vtkImagePlaneWidget::GenerateCursor() { // Construct initial points // vtkPoints* points = vtkPoints::New(VTK_DOUBLE); points->SetNumberOfPoints(4); int i; for (i = 0; i < 4; i++) { points->SetPoint(i,0.0,0.0,0.0); } vtkCellArray *cells = vtkCellArray::New(); cells->Allocate(cells->EstimateSize(2,2)); vtkIdType pts[2]; pts[0] = 0; pts[1] = 1; // horizontal segment cells->InsertNextCell(2,pts); pts[0] = 2; pts[1] = 3; // vertical segment cells->InsertNextCell(2,pts); this->CursorPolyData->SetPoints(points); points->Delete(); this->CursorPolyData->SetLines(cells); cells->Delete(); vtkPolyDataMapper* cursorMapper = vtkPolyDataMapper::New(); cursorMapper->SetInput(this->CursorPolyData); cursorMapper->SetResolveCoincidentTopologyToPolygonOffset(); this->CursorActor->SetMapper(cursorMapper); this->CursorActor->PickableOff(); this->CursorActor->VisibilityOff(); cursorMapper->Delete(); } void vtkImagePlaneWidget::GenerateText() { sprintf(this->TextBuff,"NA"); this->TextActor->SetInput(this->TextBuff); this->TextActor->ScaledTextOff(); vtkTextProperty* textprop = this->TextActor->GetTextProperty(); textprop->SetColor(1,1,1); textprop->SetFontFamilyToArial(); textprop->SetFontSize(18); textprop->BoldOff(); textprop->ItalicOff(); textprop->ShadowOff(); textprop->SetJustificationToLeft(); textprop->SetVerticalJustificationToBottom(); vtkCoordinate* coord = this->TextActor->GetPositionCoordinate(); coord->SetCoordinateSystemToNormalizedViewport(); coord->SetValue(.01, .01); this->TextActor->VisibilityOff(); } void vtkImagePlaneWidget::UpdateMargins() { double v1[3]; this->GetVector1(v1); double v2[3]; this->GetVector2(v2); double o[3]; this->PlaneSource->GetOrigin(o); double p1[3]; this->PlaneSource->GetPoint1(p1); double p2[3]; this->PlaneSource->GetPoint2(p2); double a[3]; double b[3]; double c[3]; double d[3]; double s = 0.05; double t = 0.05; int i; for ( i = 0; i < 3; i++) { a[i] = o[i] + v2[i]*(1-t); b[i] = p1[i] + v2[i]*(1-t); c[i] = o[i] + v2[i]*t; d[i] = p1[i] + v2[i]*t; } vtkPoints* marginPts = this->MarginPolyData->GetPoints(); marginPts->SetPoint(0,a); marginPts->SetPoint(1,b); marginPts->SetPoint(2,c); marginPts->SetPoint(3,d); for ( i = 0; i < 3; i++) { a[i] = o[i] + v1[i]*s; b[i] = p2[i] + v1[i]*s; c[i] = o[i] + v1[i]*(1-s); d[i] = p2[i] + v1[i]*(1-s); } marginPts->SetPoint(4,a); marginPts->SetPoint(5,b); marginPts->SetPoint(6,c); marginPts->SetPoint(7,d); this->MarginPolyData->Modified(); } void vtkImagePlaneWidget::Translate(double *p1, double *p2) { // Get the motion vector // double v[3]; v[0] = p2[0] - p1[0]; v[1] = p2[1] - p1[1]; v[2] = p2[2] - p1[2]; double *o = this->PlaneSource->GetOrigin(); double *pt1 = this->PlaneSource->GetPoint1(); double *pt2 = this->PlaneSource->GetPoint2(); double origin[3], point1[3], point2[3]; double vdrv = this->RadiusVector[0]*v[0] + \ this->RadiusVector[1]*v[1] + \ this->RadiusVector[2]*v[2]; double vdra = this->RotateAxis[0]*v[0] + \ this->RotateAxis[1]*v[1] + \ this->RotateAxis[2]*v[2]; int i; if ( this->MarginSelectMode == 8 ) // everybody comes along { for (i=0; i<3; i++) { origin[i] = o[i] + v[i]; point1[i] = pt1[i] + v[i]; point2[i] = pt2[i] + v[i]; } this->PlaneSource->SetOrigin(origin); this->PlaneSource->SetPoint1(point1); this->PlaneSource->SetPoint2(point2); } else if ( this->MarginSelectMode == 4 ) // left edge { for (i=0; i<3; i++) { origin[i] = o[i] + vdrv*this->RadiusVector[i]; point2[i] = pt2[i] + vdrv*this->RadiusVector[i]; } this->PlaneSource->SetOrigin(origin); this->PlaneSource->SetPoint2(point2); } else if ( this->MarginSelectMode == 5 ) // right edge { for (i=0; i<3; i++) { point1[i] = pt1[i] + vdrv*this->RadiusVector[i]; } this->PlaneSource->SetPoint1(point1); } else if ( this->MarginSelectMode == 6 ) // bottom edge { for (i=0; i<3; i++) { origin[i] = o[i] + vdrv*this->RadiusVector[i]; point1[i] = pt1[i] + vdrv*this->RadiusVector[i]; } this->PlaneSource->SetOrigin(origin); this->PlaneSource->SetPoint1(point1); } else if ( this->MarginSelectMode == 7 ) // top edge { for (i=0; i<3; i++) { point2[i] = pt2[i] + vdrv*this->RadiusVector[i]; } this->PlaneSource->SetPoint2(point2); } else if ( this->MarginSelectMode == 3 ) // top left corner { for (i=0; i<3; i++) { origin[i] = o[i] + vdrv*this->RadiusVector[i]; point2[i] = pt2[i] + vdrv*this->RadiusVector[i] + vdra*this->RotateAxis[i]; } this->PlaneSource->SetOrigin(origin); this->PlaneSource->SetPoint2(point2); } else if ( this->MarginSelectMode == 0 ) // bottom left corner { for (i=0; i<3; i++) { origin[i] = o[i] + vdrv*this->RadiusVector[i] + vdra*this->RotateAxis[i]; point1[i] = pt1[i] + vdra*this->RotateAxis[i]; point2[i] = pt2[i] + vdrv*this->RadiusVector[i]; } this->PlaneSource->SetOrigin(origin); this->PlaneSource->SetPoint1(point1); this->PlaneSource->SetPoint2(point2); } else if ( this->MarginSelectMode == 2 ) // top right corner { for (i=0; i<3; i++) { point1[i] = pt1[i] + vdrv*this->RadiusVector[i]; point2[i] = pt2[i] + vdra*this->RotateAxis[i]; } this->PlaneSource->SetPoint1(point1); this->PlaneSource->SetPoint2(point2); } else // bottom right corner { for (i=0; i<3; i++) { origin[i] = o[i] + vdra*this->RotateAxis[i]; point1[i] = pt1[i] + vdrv*this->RadiusVector[i] + vdra*this->RotateAxis[i]; } this->PlaneSource->SetPoint1(point1); this->PlaneSource->SetOrigin(origin); } } void vtkImagePlaneWidget::Scale(double *p1, double *p2, int vtkNotUsed(X), int Y) { // Get the motion vector // double v[3]; v[0] = p2[0] - p1[0]; v[1] = p2[1] - p1[1]; v[2] = p2[2] - p1[2]; double *o = this->PlaneSource->GetOrigin(); double *pt1 = this->PlaneSource->GetPoint1(); double *pt2 = this->PlaneSource->GetPoint2(); double* center = this->PlaneSource->GetCenter(); // Compute the scale factor // double sf = vtkMath::Norm(v) / sqrt(vtkMath::Distance2BetweenPoints(pt1,pt2)); if ( Y > this->Interactor->GetLastEventPosition()[1] ) { sf = 1.0 + sf; } else { sf = 1.0 - sf; } // Move the corner points // double origin[3], point1[3], point2[3]; for (int i=0; i<3; i++) { origin[i] = sf * (o[i] - center[i]) + center[i]; point1[i] = sf * (pt1[i] - center[i]) + center[i]; point2[i] = sf * (pt2[i] - center[i]) + center[i]; } this->PlaneSource->SetOrigin(origin); this->PlaneSource->SetPoint1(point1); this->PlaneSource->SetPoint2(point2); }