Created
October 30, 2024 18:47
-
-
Save JensMunkHansen/c949a1841bb003a9368170b05f34e869 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
// TODO: Consider making this using the newer vtkAbstractWidget and | |
// vtkWidgetRepresentation | |
// | |
#include "spsInteractionWidgetsModule.h" // For export macro | |
#include <vtk3DWidget.h> | |
class vtkActor; | |
class vtkCellPicker; | |
class vtkConeSource; | |
class vtkLineSource; | |
class vtkCubeSource; | |
class vtkPlaneSource; | |
class vtkPointPlacer; | |
class vtkPolyData; | |
class vtkPolyDataMapper; | |
class vtkProp; | |
class vtkProperty; | |
class vtkTransform; | |
class SPSINTERACTIONWIDGETS_EXPORT vtkImplicitRectangleWidget : public vtk3DWidget | |
{ | |
public: | |
static vtkImplicitRectangleWidget* New(); | |
vtkTypeMacro(vtkImplicitRectangleWidget, vtk3DWidget) | |
static const double MaxDepth; | |
static const double MinWidth; | |
static const double MinHeight; | |
///@{ | |
/** | |
* Methods that satisfy the superclass' API. | |
*/ | |
void PrintSelf(std::ostream& os, vtkIndent indent) override; | |
void SetEnabled(int) override; | |
void PlaceWidget(double bounds[6]) override; | |
void PlaceWidget() override { this->Superclass::PlaceWidget(); } | |
void PlaceWidget( | |
double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) override | |
{ | |
this->Superclass::PlaceWidget(xmin, xmax, ymin, ymax, zmin, zmax); | |
} | |
///@} | |
///@{ | |
/** | |
* Set/Get the point placer. Point placers can be used to dictate constraints | |
* on the placement of handles. As an example, see vtkBoundedPlanePointPlacer | |
* (constrains the placement of handles to a set of bounded planes) | |
* vtkFocalPlanePointPlacer (constrains placement on the focal plane) etc. | |
* The default point placer is vtkPointPlacer (which does not apply any | |
* constraints, so the handles are free to move anywhere). | |
*/ | |
virtual void SetPointPlacer(vtkPointPlacer*); | |
vtkGetObjectMacro(PointPlacer, vtkPointPlacer); | |
///@} | |
///@{ | |
/** | |
* Set/Get the resolution (number of subdivisions) of the x-axis | |
*/ | |
void SetResolutionX(int r); | |
int GetResolutionX(); | |
///@} | |
///@{ | |
/** | |
* Set/Get the resolution (number of subdivisions) of the y-axis | |
*/ | |
void SetResolutionY(int r); | |
int GetResolutionY(); | |
///@} | |
///@{ | |
/** | |
* Set/Get the origin of the rectamgle | |
*/ | |
double* GetOrigin() VTK_SIZEHINT(3); | |
void GetOrigin(double xyz[3]); | |
///@} | |
///@{ | |
/** | |
* Get the center of the rectangular box. This must be different | |
* from the origin for spinning to work. | |
*/ | |
double* GetCenter() VTK_SIZEHINT(3); | |
void GetCenter(double xyz[3]); | |
///@} | |
double GetWidth(); | |
void SetWidth(double width); | |
double GetHeight(); | |
void SetHeight(double height); | |
double GetDepth(); | |
void SetDepth(double height); | |
void SetPlaneProperty(vtkProperty*); | |
vtkGetObjectMacro(PlaneProperty, vtkProperty); | |
void SetSelectedPlaneProperty(vtkProperty*); | |
vtkGetObjectMacro(SelectedPlaneProperty, vtkProperty); | |
void SetSelectedPlaneCtrlProperty(vtkProperty*); | |
vtkGetObjectMacro(SelectedPlaneCtrlProperty, vtkProperty); | |
void SetHandleProperty(vtkProperty*); | |
vtkGetObjectMacro(HandleProperty, vtkProperty); | |
void SetSelectedHandleProperty(vtkProperty*); | |
vtkGetObjectMacro(SelectedHandleProperty, vtkProperty); | |
void SetSelectedHandleCtrlProperty(vtkProperty*); | |
vtkGetObjectMacro(SelectedHandleCtrlProperty, vtkProperty); | |
void SetSelectedPolyHandleProperty(vtkProperty*); | |
vtkGetObjectMacro(SelectedPolyHandleProperty, vtkProperty); | |
void SetPolyHandleProperty(vtkProperty*); | |
vtkGetObjectMacro(PolyHandleProperty, vtkProperty); | |
void SetCubeProperty(vtkProperty*); | |
vtkGetObjectMacro(CubeProperty, vtkProperty); | |
// Set operation must be handled explicitly (easy we hide it!) | |
// void SetUserTransform(vtkTransform*); | |
vtkGetObjectMacro(UserTransform, vtkTransform); | |
vtkGetObjectMacro(Handle, vtkPolyData); | |
void SetHandle(vtkPolyData* args); | |
///@{ | |
/** | |
* Height offset at which points may be placed on the polygonal surface. | |
* If you specify a non-zero value here, be sure to compute cell normals | |
* on your input polygonal data (easily done with vtkPolyDataNormals). | |
*/ | |
vtkSetMacro(DistanceOffset, double); | |
vtkGetMacro(DistanceOffset, double); | |
///@} | |
vtkGetObjectMacro(PlaneSource, vtkPlaneSource); | |
virtual void UpdateCamera(); | |
protected: | |
virtual void ShowBox(); | |
vtkImplicitRectangleWidget(); | |
~vtkImplicitRectangleWidget(); | |
void ReleaseHandle(); | |
enum WidgetState | |
{ | |
Start = 0, | |
Moving, | |
MovingOnSurface, | |
Scaling, | |
Pushing, | |
Rotating, | |
Spinning, | |
SpinningAxis, | |
Outside, | |
Pinching // Semantic zooming by spreading two fingers | |
}; | |
// handles the events | |
static void ProcessEvents( | |
vtkObject* object, unsigned long event, void* clientdata, void* calldata); | |
// ProcessEvents() dispatches to these methods. | |
void OnLeftButtonDown(); | |
void OnLeftButtonUp(); | |
void OnMiddleButtonDown(); | |
void OnMiddleButtonUp(); | |
void OnRightButtonDown(); | |
void OnRightButtonUp(); | |
void OnMouseMove(); | |
void OnStartPinch(); | |
void OnPinch(); | |
void OnEndPinch(); | |
void SelectRepresentation(); | |
void SizeHandles() override; | |
void HighlightRectangle(int highlight); | |
void HighlightHandle(vtkProp* prop); | |
int State; | |
vtkTransform* UserTransform; | |
vtkCubeSource* CubeSource; | |
vtkPolyDataMapper* CubeMapper; | |
vtkActor* CubeActor; | |
vtkPlaneSource* PlaneSource; | |
vtkPolyDataMapper* PlaneMapper; | |
vtkActor* PlaneActor; | |
double Center[3]; | |
double Origin[3]; | |
// the handle cone | |
vtkConeSource* ConeSource; | |
vtkPolyDataMapper* ConeMapper; | |
vtkActor* ConeActor; | |
// the normal line | |
vtkLineSource* LineSource; | |
vtkPolyDataMapper* LineMapper; | |
vtkActor* LineActor; | |
vtkPolyDataMapper* PolyDataMapper; | |
vtkActor* PolyDataActor; | |
vtkPointPlacer* PointPlacer; | |
// Do the picking | |
vtkCellPicker* HandlePicker; | |
vtkCellPicker* PlanePicker; | |
vtkActor* CurrentHandle; | |
int LastPickValid; | |
double HandleSizeFactor; | |
// Properties used to control the appearance of selected objects and | |
// the manipulator in general. | |
vtkProperty* HandleProperty; | |
vtkProperty* SelectedHandleProperty; | |
vtkProperty* SelectedHandleCtrlProperty; | |
vtkProperty* PlaneProperty; | |
vtkProperty* SelectedPlaneProperty; | |
vtkProperty* SelectedPlaneCtrlProperty; | |
vtkProperty* PolyHandleProperty; | |
vtkProperty* SelectedPolyHandleProperty; | |
vtkProperty* CubeProperty; | |
double DistanceOffset; | |
double Width; | |
double Height; | |
double Depth; | |
// Experimental - some of it is for sure redundant | |
double StartEventPosition[3]; | |
double WorldPosition[3]; | |
// Like done in vtkIterativeClosestPoint | |
vtkPolyData* Handle; | |
// Register internal Pickers within PickingManager | |
void RegisterPickers() override; | |
void Rotate(int X, int Y, double* p1, double* p2, double* vpn); | |
void Spin(double* p1, double* p2, double* spinAxis); | |
void Scale(double* p1, double* p2, int X, int Y); | |
void Translate(double* p1, double* p2); | |
void Push(double* p1, double* p2); | |
void CreateDefaultProperties(); | |
void PositionHandle(); | |
// Taken from vtkAbstractPolygonalHandleRepresentation3D | |
void MoveFocusRequest( | |
const double* p1, const double* p2, const double currPos[2], double center[3]); | |
private: | |
vtkImplicitRectangleWidget(const vtkImplicitRectangleWidget&) = delete; | |
void operator=(const vtkImplicitRectangleWidget&) = delete; | |
}; | |
// TODO: - Convert this to the new way of making widgets (postponed) | |
#include <vtkActor.h> | |
#include <vtkAssemblyNode.h> | |
#include <vtkAssemblyPath.h> | |
#include <vtkCallbackCommand.h> | |
#include <vtkCamera.h> | |
#include <vtkCellPicker.h> | |
#include <vtkConeSource.h> | |
#include <vtkCubeSource.h> | |
#include <vtkImplicitRectangleWidget.h> | |
#include <vtkLineSource.h> | |
#include <vtkMatrix4x4.h> | |
#include <vtkObjectFactory.h> | |
#include <vtkPickingManager.h> | |
#include <vtkPlaneSource.h> | |
#include <vtkPointPlacer.h> | |
#include <vtkPolyDataCollection.h> | |
#include <vtkPolyDataMapper.h> | |
#include <vtkPropPicker.h> | |
#include <vtkProperty.h> | |
#include <vtkRenderWindowInteractor.h> | |
#include <vtkRenderer.h> | |
#include <vtkTransform.h> | |
#include <algorithm> | |
#ifndef SQUARE | |
#define SQUARE(z) ((z) * (z)) | |
#endif // SQUARE | |
vtkStandardNewMacro(vtkImplicitRectangleWidget); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, PlaneProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, SelectedPlaneProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, SelectedPlaneCtrlProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, HandleProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, SelectedHandleProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, SelectedHandleCtrlProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, PolyHandleProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, SelectedPolyHandleProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, CubeProperty, vtkProperty); | |
vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, PointPlacer, vtkPointPlacer); | |
// Do not allow setting this - or ensure this is propagated to all actors | |
// vtkCxxSetObjectMacro(vtkImplicitRectangleWidget, UserTransform, vtkTransform) | |
const double vtkImplicitRectangleWidget::MaxDepth = 1000.0; | |
const double vtkImplicitRectangleWidget::MinWidth = 0.01; | |
const double vtkImplicitRectangleWidget::MinHeight = 0.01; | |
void vtkImplicitRectangleWidget::ReleaseHandle() | |
{ | |
if (this->Handle) | |
{ | |
this->Handle->UnRegister(this); | |
this->Handle = nullptr; | |
} | |
} | |
void vtkImplicitRectangleWidget::SetHandle(vtkPolyData* args) | |
{ | |
// TODO: Verify nullptr argument is okay | |
if (this->Handle == args) | |
{ | |
return; | |
} | |
if (this->Handle) | |
{ | |
this->ReleaseHandle(); | |
} | |
if (args) | |
{ | |
args->Register(this); | |
} | |
this->Handle = args; | |
if (this->PolyDataActor) | |
{ | |
this->HandlePicker->DeletePickList(this->PolyDataActor); | |
this->CurrentRenderer->RemoveActor(this->PolyDataActor); | |
} | |
// Extra stuff needed | |
this->PolyDataMapper->SetInputData(this->Handle); | |
this->PolyDataActor->SetMapper(this->PolyDataMapper); | |
this->PolyDataActor->SetUserTransform(this->UserTransform); | |
this->HandlePicker->AddPickList(this->PolyDataActor); | |
this->CurrentRenderer->AddActor(this->PolyDataActor); | |
this->Modified(); | |
} | |
void vtkImplicitRectangleWidget::ShowBox() | |
{ | |
if (this->Interactor->GetKeyCode() == 'b' || this->Interactor->GetKeyCode() == 'B') | |
{ | |
// Show/hide clipping boxxs | |
// TODO: After moving camera verify bounds for box equal bounds for frustum | |
if (this->CurrentRenderer->HasViewProp(this->CubeActor)) | |
{ | |
this->CurrentRenderer->RemoveActor(this->CubeActor); | |
} | |
else | |
{ | |
this->CurrentRenderer->RemoveActor(this->CubeActor); | |
this->CurrentRenderer->AddActor(this->CubeActor); | |
} | |
this->Interactor->Render(); | |
} | |
else if (this->Interactor->GetKeyCode() == 'a' || this->Interactor->GetKeyCode() == 'A') | |
{ | |
// Show/hide actor for polydata | |
if (this->CurrentRenderer->HasViewProp(this->PolyDataActor)) | |
{ | |
this->CurrentRenderer->RemoveActor(this->PolyDataActor); | |
} | |
else | |
{ | |
this->CurrentRenderer->RemoveActor(this->PolyDataActor); | |
this->CurrentRenderer->AddActor(this->PolyDataActor); | |
} | |
this->Interactor->Render(); | |
} | |
else if (this->Interactor->GetKeyCode() == 'h' || this->Interactor->GetKeyCode() == 'H') | |
{ | |
if (this->CurrentRenderer->HasViewProp(this->ConeActor)) | |
{ | |
this->CurrentRenderer->RemoveActor(this->ConeActor); | |
this->CurrentRenderer->RemoveActor(this->LineActor); | |
} | |
else | |
{ | |
this->CurrentRenderer->RemoveActor(this->ConeActor); | |
this->CurrentRenderer->RemoveActor(this->LineActor); | |
this->CurrentRenderer->AddActor(this->ConeActor); | |
this->CurrentRenderer->AddActor(this->LineActor); | |
} | |
this->Interactor->Render(); | |
} | |
} | |
vtkImplicitRectangleWidget::vtkImplicitRectangleWidget() | |
{ | |
// The user must enable this widget to use it | |
this->Enabled = 0; | |
this->EventCallbackCommand->SetCallback(vtkImplicitRectangleWidget::ProcessEvents); | |
this->State = vtkImplicitRectangleWidget::Start; | |
this->Width = 15; | |
this->Height = 15; | |
this->Depth = 30.0; | |
// Transform used for all actors | |
this->UserTransform = vtkTransform::New(); | |
this->UserTransform->Identity(); | |
this->PlaneSource = vtkPlaneSource::New(); | |
this->PlaneSource->SetXResolution(1); | |
this->PlaneSource->SetYResolution(1); | |
this->CubeSource = vtkCubeSource::New(); | |
this->CubeSource->SetBounds(-0.5 * this->Width, 0.5 * this->Width, -0.5 * this->Height, | |
0.5 * this->Width, 0.0, this->Depth); | |
this->CubeMapper = vtkPolyDataMapper::New(); | |
this->CubeMapper->SetInputConnection(this->CubeSource->GetOutputPort()); | |
this->CubeActor = vtkActor::New(); | |
this->CubeActor->SetMapper(this->CubeMapper); | |
this->CubeActor->SetUserTransform(this->UserTransform); | |
this->Origin[0] = 0.0; | |
this->Origin[1] = 0.0; | |
this->Origin[2] = 0.0; | |
this->PlaneSource->SetOrigin(-0.5 * this->Width, -0.5 * this->Height, 0.0); | |
this->PlaneSource->SetPoint1(0.5 * this->Width, -0.5 * this->Height, 0.0); | |
this->PlaneSource->SetPoint2(-0.5 * this->Width, 0.5 * this->Height, 0.0); | |
this->PlaneSource->Update(); // Get the output before pipeline executes | |
this->PlaneMapper = vtkPolyDataMapper::New(); | |
this->PlaneMapper->SetInputConnection(this->PlaneSource->GetOutputPort()); | |
this->PlaneActor = vtkActor::New(); | |
this->PlaneActor->SetMapper(this->PlaneMapper); | |
this->PlaneActor->SetUserTransform(this->UserTransform); | |
this->Center[0] = 0.0; | |
this->Center[1] = 0.0; | |
this->Center[2] = | |
1.0; // Needs to be different than origin for computing spin. TODO: Add offset elsewhere | |
this->ConeSource = vtkConeSource::New(); | |
this->ConeSource->SetResolution(12); | |
this->ConeSource->SetAngle(25.0); | |
this->ConeSource->SetRadius(4.0); | |
// Direction of the cone, parallel to (Center - Origin) | |
double direction[3] = { 0.0, 0.0, 1.0 }; | |
this->ConeSource->SetDirection(direction); | |
this->ConeMapper = vtkPolyDataMapper::New(); | |
this->ConeMapper->SetInputConnection(this->ConeSource->GetOutputPort()); | |
this->ConeActor = vtkActor::New(); | |
this->ConeActor->SetMapper(this->ConeMapper); | |
this->ConeActor->SetUserTransform(this->UserTransform); | |
// Create the line to the handle | |
this->LineSource = vtkLineSource::New(); | |
this->LineSource->SetResolution(1); | |
this->LineMapper = vtkPolyDataMapper::New(); | |
this->LineMapper->SetInputConnection(this->LineSource->GetOutputPort()); | |
this->LineActor = vtkActor::New(); | |
this->LineActor->SetMapper(this->LineMapper); | |
this->LineActor->SetUserTransform(this->UserTransform); | |
this->PolyDataMapper = vtkPolyDataMapper::New(); | |
this->PolyDataActor = vtkActor::New(); | |
this->PointPlacer = vtkPointPlacer::New(); | |
double bounds[6]; | |
this->PlaneSource->GetOutput()->GetBounds(bounds); | |
// Set InitialLength of parent class (otherwise unitialized variable) | |
this->InitialLength = sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) + | |
(bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) + | |
(bounds[5] - bounds[4]) * (bounds[5] - bounds[4])); | |
// Manage the picking stuff | |
this->HandlePicker = vtkCellPicker::New(); | |
this->HandlePicker->SetTolerance(0.001); | |
this->HandlePicker->AddPickList(this->ConeActor); | |
this->HandlePicker->AddPickList(this->LineActor); | |
this->HandlePicker->PickFromListOn(); | |
this->PlanePicker = vtkCellPicker::New(); | |
this->PlanePicker->SetTolerance(0.005); // need some fluff | |
this->PlanePicker->AddPickList(this->PlaneActor); | |
this->PlanePicker->PickFromListOn(); | |
this->CurrentHandle = nullptr; | |
this->LastPickValid = 0; | |
this->HandleSizeFactor = 1.25; | |
this->SetHandleSize(0.15); | |
// Set up the initial properties | |
this->CreateDefaultProperties(); | |
this->DistanceOffset = 0.0; | |
this->StartEventPosition[0] = this->StartEventPosition[1] = this->StartEventPosition[2] = 0.0; | |
this->WorldPosition[0] = this->WorldPosition[1] = this->WorldPosition[2] = 0.0; | |
this->Handle = nullptr; | |
// Initial creation of the widget, serves to initialize it | |
// Call PlaceWidget() LAST in the constructor as it depends on ivar values. | |
this->PlaceWidget(bounds); | |
} | |
void vtkImplicitRectangleWidget::SelectRepresentation() | |
{ | |
if (!this->CurrentRenderer) | |
{ | |
return; | |
} | |
else | |
{ | |
this->CurrentRenderer->RemoveActor(this->PlaneActor); | |
this->CurrentRenderer->RemoveActor(this->PolyDataActor); | |
this->CurrentRenderer->RemoveActor(this->CubeActor); | |
this->CurrentRenderer->AddActor(this->PlaneActor); | |
this->CurrentRenderer->AddActor(this->PolyDataActor); | |
this->CurrentRenderer->AddActor(this->CubeActor); | |
} | |
} | |
void vtkImplicitRectangleWidget::PlaceWidget(double vtkNotUsed(bounds)[6]) | |
{ | |
this->PlaneSource->Update(); | |
this->CubeSource->Update(); | |
this->PositionHandle(); | |
this->SizeHandles(); | |
} | |
vtkImplicitRectangleWidget::~vtkImplicitRectangleWidget() | |
{ | |
this->PlaneActor->Delete(); | |
this->PlaneMapper->Delete(); | |
this->PlaneSource->Delete(); | |
this->CubeActor->Delete(); | |
this->CubeMapper->Delete(); | |
this->CubeSource->Delete(); | |
this->ConeActor->Delete(); | |
this->ConeMapper->Delete(); | |
this->ConeSource->Delete(); | |
this->LineActor->Delete(); | |
this->LineMapper->Delete(); | |
this->LineSource->Delete(); | |
this->HandlePicker->Delete(); | |
this->PlanePicker->Delete(); | |
if (this->PolyDataActor) | |
{ | |
this->PolyDataActor->Delete(); | |
} | |
if (this->PolyDataMapper) | |
{ | |
this->PolyDataMapper->Delete(); | |
} | |
if (this->CubeProperty) | |
{ | |
this->CubeProperty->Delete(); | |
this->CubeProperty = nullptr; | |
} | |
if (this->HandleProperty) | |
{ | |
this->HandleProperty->Delete(); | |
this->HandleProperty = nullptr; | |
} | |
if (this->SelectedHandleProperty) | |
{ | |
this->SelectedHandleProperty->Delete(); | |
this->SelectedHandleProperty = nullptr; | |
} | |
if (this->SelectedHandleCtrlProperty) | |
{ | |
this->SelectedHandleCtrlProperty->Delete(); | |
this->SelectedHandleCtrlProperty = nullptr; | |
} | |
if (this->PlaneProperty) | |
{ | |
this->PlaneProperty->Delete(); | |
this->PlaneProperty = nullptr; | |
} | |
if (this->SelectedPlaneProperty) | |
{ | |
this->SelectedPlaneProperty->Delete(); | |
this->SelectedPlaneProperty = nullptr; | |
} | |
if (this->SelectedPlaneCtrlProperty) | |
{ | |
this->SelectedPlaneCtrlProperty->Delete(); | |
this->SelectedPlaneCtrlProperty = nullptr; | |
} | |
if (this->PolyHandleProperty) | |
{ | |
this->PolyHandleProperty->Delete(); | |
this->PolyHandleProperty = nullptr; | |
} | |
if (this->SelectedPolyHandleProperty) | |
{ | |
this->SelectedPolyHandleProperty->Delete(); | |
this->SelectedPolyHandleProperty = nullptr; | |
} | |
this->UserTransform->Delete(); | |
this->UserTransform = nullptr; | |
this->ReleaseHandle(); | |
this->SetPointPlacer(nullptr); | |
} | |
void vtkImplicitRectangleWidget::PrintSelf(std::ostream& os, vtkIndent indent) | |
{ | |
this->Superclass::PrintSelf(os, indent); | |
os << indent << "Width: " << this->Width << endl; | |
os << indent << "Height: " << this->Height << endl; | |
os << indent << "Depth: " << this->Depth << endl; | |
if (this->HandleProperty) | |
{ | |
os << indent << "Handle Property: " << this->HandleProperty << "\n"; | |
} | |
else | |
{ | |
os << indent << "Handle Property: (none)\n"; | |
} | |
if (this->SelectedHandleProperty) | |
{ | |
os << indent << "Selected Handle Property: " << this->SelectedHandleProperty << "\n"; | |
} | |
else | |
{ | |
os << indent << "SelectedHandle Property: (none)\n"; | |
} | |
if (this->PlaneProperty) | |
{ | |
os << indent << "Plane Property: " << this->PlaneProperty << "\n"; | |
} | |
else | |
{ | |
os << indent << "Plane Property: (none)\n"; | |
} | |
if (this->SelectedPlaneProperty) | |
{ | |
os << indent << "Selected Plane Property: " << this->SelectedPlaneProperty << "\n"; | |
} | |
else | |
{ | |
os << indent << "Selected Plane Property: (none)\n"; | |
} | |
double* baseOrigin = this->Origin; | |
double* baseCenter = this->Center; | |
double o[3]; | |
double c[3]; | |
this->UserTransform->TransformPoint(baseOrigin, o); | |
this->UserTransform->TransformPoint(baseCenter, c); | |
os << indent << "Origin: [" << o[0] << ", " << o[1] << ", " << o[2] << "] (explicit)\n"; | |
os << indent << "Center: [" << c[0] << ", " << c[1] << ", " << c[2] << "] (explicit)\n"; | |
if (this->PointPlacer) | |
{ | |
os << indent << "PointPlacer:\n"; | |
this->PointPlacer->PrintSelf(os, indent.GetNextIndent()); | |
} | |
else | |
{ | |
os << indent << "PointPlacer: (none)\n"; | |
} | |
} | |
void vtkImplicitRectangleWidget::SetEnabled(int enabling) | |
{ | |
if (!this->Interactor) | |
{ | |
vtkErrorMacro(<< "The interactor must be set prior to enabling/disabling widget"); | |
return; | |
} | |
if (enabling) //----------------------------------------------------------- | |
{ | |
vtkDebugMacro(<< "Enabling sector 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 == nullptr) | |
{ | |
return; | |
} | |
} | |
this->Enabled = 1; | |
// listen for the following events | |
vtkRenderWindowInteractor* i = this->Interactor; | |
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); | |
i->AddObserver(vtkCommand::StartPinchEvent, this->EventCallbackCommand, this->Priority); | |
i->AddObserver(vtkCommand::PinchEvent, this->EventCallbackCommand, this->Priority); | |
i->AddObserver(vtkCommand::EndPinchEvent, this->EventCallbackCommand, this->Priority); | |
i->AddObserver(vtkCommand::KeyPressEvent, this->EventCallbackCommand, this->Priority); | |
this->CurrentRenderer->AddActor(this->CubeActor); | |
this->CubeActor->SetProperty(this->CubeProperty); | |
// Add the plane | |
this->CurrentRenderer->AddActor(this->PlaneActor); | |
this->PlaneActor->SetProperty(this->PlaneProperty); | |
// Add the handle | |
this->CurrentRenderer->AddActor(this->LineActor); | |
this->LineActor->SetProperty(this->HandleProperty); | |
this->CurrentRenderer->AddActor(this->ConeActor); | |
this->ConeActor->SetProperty(this->HandleProperty); | |
this->CurrentRenderer->AddActor(this->PolyDataActor); | |
this->SelectRepresentation(); | |
this->RegisterPickers(); | |
this->InvokeEvent(vtkCommand::EnableEvent, nullptr); | |
} | |
else // disabling---------------------------------------------------------- | |
{ | |
vtkDebugMacro(<< "Disabling sector 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 sector | |
this->CurrentRenderer->RemoveActor(this->PlaneActor); | |
// turn off the handle | |
this->CurrentRenderer->RemoveActor(this->LineActor); | |
this->CurrentRenderer->RemoveActor(this->ConeActor); | |
// turn of the polygonal actor | |
this->CurrentRenderer->RemoveActor(this->PolyDataActor); | |
this->CurrentHandle = nullptr; | |
this->InvokeEvent(vtkCommand::DisableEvent, nullptr); | |
this->SetCurrentRenderer(nullptr); | |
this->UnRegisterPickers(); | |
} | |
this->UpdateCamera(); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::SetResolutionX(int r) | |
{ | |
this->PlaneSource->SetXResolution(r); | |
} | |
int vtkImplicitRectangleWidget::GetResolutionX() | |
{ | |
return this->PlaneSource->GetXResolution(); | |
} | |
void vtkImplicitRectangleWidget::SetResolutionY(int r) | |
{ | |
this->PlaneSource->SetYResolution(r); | |
} | |
int vtkImplicitRectangleWidget::GetResolutionY() | |
{ | |
return this->PlaneSource->GetYResolution(); | |
} | |
void vtkImplicitRectangleWidget::PositionHandle() | |
{ | |
double handleLength; | |
double handleOrigin[3]; | |
double origin[3]; | |
// Right | |
handleLength = 3.0 * this->Height; | |
origin[0] = origin[1] = origin[2] = 0.0; | |
handleOrigin[0] = handleOrigin[1] = 0.0; | |
handleOrigin[2] = -handleLength; | |
// Update line source and cone source | |
this->LineSource->SetPoint1(origin); | |
this->LineSource->SetPoint2(handleOrigin); | |
this->ConeSource->SetCenter(handleOrigin); | |
// Add center property for widget (to rotate about) | |
this->SelectRepresentation(); | |
} | |
void vtkImplicitRectangleWidget::HighlightHandle(vtkProp* prop) | |
{ | |
// first unhighlight anything picked | |
if (this->CurrentHandle) | |
{ | |
this->CurrentHandle->SetProperty(this->HandleProperty); | |
} | |
// Only the current part of the handle is selected | |
this->CurrentHandle = static_cast<vtkActor*>(prop); | |
if (this->CurrentHandle) | |
{ | |
this->ValidPick = 1; | |
this->HandlePicker->GetPickPosition(this->LastPickPosition); | |
if (this->Interactor->GetControlKey()) | |
{ | |
this->CurrentHandle->SetProperty(this->SelectedHandleCtrlProperty); | |
} | |
else | |
{ | |
this->CurrentHandle->SetProperty(this->SelectedHandleProperty); | |
} | |
} | |
} | |
double vtkImplicitRectangleWidget::GetWidth() | |
{ | |
return this->Width; | |
} | |
double vtkImplicitRectangleWidget::GetHeight() | |
{ | |
return this->Height; | |
} | |
double vtkImplicitRectangleWidget::GetDepth() | |
{ | |
return this->Depth; | |
} | |
void vtkImplicitRectangleWidget::SetWidth(double width) | |
{ | |
if (width != this->Width) | |
{ | |
if (width < vtkImplicitRectangleWidget::MinWidth) | |
{ | |
// We do not support very small widths. | |
return; | |
} | |
this->Width = width; | |
this->PlaneSource->SetOrigin(-0.5 * this->Width, -0.5 * this->Height, 0.0); | |
this->PlaneSource->SetPoint1(0.5 * this->Width, -0.5 * this->Height, 0.0); | |
this->PlaneSource->SetPoint2(-0.5 * this->Width, 0.5 * this->Height, 0.0); | |
this->PlaneSource->Update(); // Get the output before pipeline executes | |
double bounds[6]; | |
this->CubeSource->GetBounds(bounds); | |
bounds[0] = -0.5 * this->Width; | |
bounds[1] = 0.5 * this->Width; | |
this->CubeSource->SetBounds(bounds); | |
this->CubeSource->Update(); | |
this->Modified(); | |
} | |
} | |
void vtkImplicitRectangleWidget::SetHeight(double height) | |
{ | |
if (height != this->Height) | |
{ | |
if (height < vtkImplicitRectangleWidget::MinHeight) | |
{ | |
return; | |
} | |
this->Height = height; | |
this->PlaneSource->SetOrigin(-0.5 * this->Width, -0.5 * this->Height, 0.0); | |
this->PlaneSource->SetPoint1(0.5 * this->Width, -0.5 * this->Height, 0.0); | |
this->PlaneSource->SetPoint2(-0.5 * this->Width, 0.5 * this->Height, 0.0); | |
this->PlaneSource->Update(); // Get the output before pipeline executes | |
double bounds[6]; | |
this->CubeSource->GetBounds(bounds); | |
bounds[2] = -0.5 * this->Height; | |
bounds[3] = 0.5 * this->Height; | |
this->CubeSource->SetBounds(bounds); | |
this->CubeSource->Update(); | |
this->Modified(); | |
} | |
} | |
void vtkImplicitRectangleWidget::SetDepth(double depth) | |
{ | |
if (this->Depth != depth) | |
{ | |
if (depth > vtkImplicitRectangleWidget::MaxDepth) | |
{ | |
return; | |
} | |
this->Depth = depth; | |
double bounds[6]; | |
this->CubeSource->GetBounds(bounds); | |
bounds[4] = 0.0; | |
bounds[5] = this->Depth; | |
this->CubeSource->SetBounds(bounds); | |
this->CubeSource->Update(); | |
this->Modified(); | |
} | |
} | |
double* vtkImplicitRectangleWidget::GetOrigin() | |
{ | |
return this->Origin; | |
} | |
void vtkImplicitRectangleWidget::GetOrigin(double xyz[3]) | |
{ | |
std::copy(this->Origin, this->Origin + 3, xyz); | |
} | |
double* vtkImplicitRectangleWidget::GetCenter() | |
{ | |
return this->Center; | |
} | |
void vtkImplicitRectangleWidget::GetCenter(double xyz[3]) | |
{ | |
std::copy(this->Center, this->Center + 3, xyz); | |
} | |
void vtkImplicitRectangleWidget::ProcessEvents( | |
vtkObject* vtkNotUsed(object), unsigned long event, void* clientdata, void* vtkNotUsed(calldata)) | |
{ | |
vtkImplicitRectangleWidget* self = reinterpret_cast<vtkImplicitRectangleWidget*>(clientdata); | |
switch (event) | |
{ | |
case vtkCommand::LeftButtonPressEvent: | |
self->OnLeftButtonDown(); | |
break; | |
case vtkCommand::LeftButtonReleaseEvent: | |
self->OnLeftButtonUp(); | |
break; | |
case vtkCommand::MiddleButtonPressEvent: | |
self->OnMiddleButtonDown(); | |
break; | |
case vtkCommand::MiddleButtonReleaseEvent: | |
self->OnMiddleButtonUp(); | |
break; | |
case vtkCommand::RightButtonPressEvent: | |
self->OnRightButtonDown(); | |
break; | |
case vtkCommand::RightButtonReleaseEvent: | |
self->OnRightButtonUp(); | |
break; | |
case vtkCommand::MouseMoveEvent: | |
self->OnMouseMove(); | |
break; | |
case vtkCommand::StartPinchEvent: | |
self->OnStartPinch(); | |
break; | |
case vtkCommand::PinchEvent: | |
self->OnPinch(); | |
break; | |
case vtkCommand::EndPinchEvent: | |
self->OnEndPinch(); | |
break; | |
case vtkCommand::KeyPressEvent: | |
self->ShowBox(); | |
break; | |
} | |
} | |
void vtkImplicitRectangleWidget::OnLeftButtonDown() | |
{ | |
// TODO: Allow spinning when PolyActor is hit | |
vtkDebugMacro(<< __FUNCTION__); | |
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 = vtkImplicitRectangleWidget::Outside; | |
return; | |
} | |
vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker); | |
// Some experimental stuff (take from new widget design) | |
this->StartEventPosition[0] = static_cast<double>(X); | |
this->StartEventPosition[1] = static_cast<double>(Y); | |
this->StartEventPosition[2] = 0.0; | |
if (path != nullptr) | |
{ | |
vtkProp* prop = path->GetFirstNode()->GetViewProp(); | |
if (prop == this->ConeActor || prop == this->LineActor) | |
{ | |
if (this->Interactor->GetControlKey()) | |
{ | |
this->State = vtkImplicitRectangleWidget::SpinningAxis; | |
this->HighlightHandle(path->GetFirstNode()->GetViewProp()); | |
} | |
else | |
{ | |
this->State = vtkImplicitRectangleWidget::Rotating; | |
this->HighlightHandle(path->GetFirstNode()->GetViewProp()); | |
} | |
} | |
else if (prop == this->PolyDataActor) | |
{ | |
// Hit if polydata is clicked (the transducer) | |
if (this->Interactor->GetShiftKey()) | |
{ | |
this->State = vtkImplicitRectangleWidget::MovingOnSurface; | |
} | |
else if (this->Interactor->GetControlKey()) | |
{ | |
// When polydata is hit and constrol pressed - spin around x-axis | |
this->State = vtkImplicitRectangleWidget::Spinning; | |
this->HighlightHandle(path->GetFirstNode()->GetViewProp()); | |
} | |
else | |
{ | |
this->State = vtkImplicitRectangleWidget::Moving; | |
} | |
} | |
} | |
else | |
{ | |
path = this->GetAssemblyPath(X, Y, 0., this->PlanePicker); | |
if (path != nullptr) | |
{ | |
if (this->Interactor->GetControlKey()) | |
{ | |
this->State = vtkImplicitRectangleWidget::SpinningAxis; | |
this->HighlightRectangle(1); | |
} | |
else if (this->Interactor->GetShiftKey()) | |
{ | |
this->State = vtkImplicitRectangleWidget::MovingOnSurface; | |
} | |
else | |
{ | |
vtkDebugMacro(<< "Moving"); | |
this->State = vtkImplicitRectangleWidget::Moving; | |
} | |
} | |
else | |
{ | |
this->State = vtkImplicitRectangleWidget::Outside; | |
this->ValidPick = 0; | |
this->HighlightHandle(nullptr); | |
return; | |
} | |
} | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->StartInteraction(); | |
this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::OnLeftButtonUp() | |
{ | |
vtkDebugMacro(<< __FUNCTION__); | |
if (this->State == vtkImplicitRectangleWidget::Outside || | |
this->State == vtkImplicitRectangleWidget::Start) | |
{ | |
return; | |
} | |
this->State = vtkImplicitRectangleWidget::Start; | |
this->HighlightHandle(nullptr); | |
this->HighlightRectangle(0); | |
this->SizeHandles(); | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->EndInteraction(); | |
this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::SizeHandles() | |
{ | |
double radius = this->vtk3DWidget::SizeHandles(this->HandleSizeFactor); | |
if (this->ValidPick && !this->LastPickValid) | |
{ | |
// Adjust factor to preserve old radius. | |
double oldradius = this->ConeSource->GetRadius(); | |
if (oldradius != 0 && radius != 0) | |
{ | |
this->HandleSizeFactor = oldradius / radius; | |
radius = oldradius; | |
} | |
} | |
this->LastPickValid = this->ValidPick; | |
// Set the height and radius of the cone | |
this->ConeSource->SetRadius(radius); | |
this->ConeSource->SetHeight(2 * radius); | |
} | |
void vtkImplicitRectangleWidget::OnMiddleButtonDown() | |
{ | |
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 = vtkImplicitRectangleWidget::Outside; | |
return; | |
} | |
// Okay, we can process this. If anything is picked, then we | |
// can start pushing the plane. | |
vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker); | |
if (path != nullptr) | |
{ | |
this->State = vtkImplicitRectangleWidget::Pushing; | |
this->HighlightRectangle(1); | |
this->HighlightHandle(path->GetFirstNode()->GetViewProp()); | |
} | |
else | |
{ | |
path = this->GetAssemblyPath(X, Y, 0., this->PlanePicker); | |
if (path == nullptr) // nothing picked | |
{ | |
this->State = vtkImplicitRectangleWidget::Outside; | |
return; | |
} | |
else | |
{ | |
this->State = vtkImplicitRectangleWidget::Pushing; | |
this->HighlightRectangle(1); | |
} | |
} | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->StartInteraction(); | |
this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::OnMiddleButtonUp() | |
{ | |
vtkDebugMacro(<< __FUNCTION__); | |
if (this->State == vtkImplicitRectangleWidget::Outside || | |
this->State == vtkImplicitRectangleWidget::Start) | |
{ | |
return; | |
} | |
this->State = vtkImplicitRectangleWidget::Start; | |
this->HighlightRectangle(0); | |
this->HighlightHandle(nullptr); | |
this->SizeHandles(); | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->EndInteraction(); | |
this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::OnRightButtonDown() | |
{ | |
vtkDebugMacro(<< __FUNCTION__); | |
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 = vtkImplicitRectangleWidget::Outside; | |
return; | |
} | |
// Okay, we can process this. Try to pick handles first; | |
// if no handles picked, then pick the bounding box. | |
vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker); | |
if (path != nullptr) | |
{ | |
this->State = vtkImplicitRectangleWidget::Scaling; | |
this->HighlightRectangle(1); | |
this->HighlightHandle(path->GetFirstNode()->GetViewProp()); | |
} | |
else // see if we picked the plane or a normal | |
{ | |
path = this->GetAssemblyPath(X, Y, 0., this->PlanePicker); | |
if (path == nullptr) | |
{ | |
this->State = vtkImplicitRectangleWidget::Outside; | |
this->ValidPick = 0; // I believe this is how it should be | |
return; | |
} | |
else | |
{ | |
this->State = vtkImplicitRectangleWidget::Scaling; | |
this->HighlightRectangle(1); | |
} | |
} | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->StartInteraction(); | |
this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::OnRightButtonUp() | |
{ | |
vtkDebugMacro(<< __FUNCTION__); | |
if (this->State == vtkImplicitRectangleWidget::Outside || | |
this->State == vtkImplicitRectangleWidget::Start) | |
{ | |
return; | |
} | |
this->State = vtkImplicitRectangleWidget::Start; | |
this->HighlightRectangle(0); | |
this->SizeHandles(); | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->EndInteraction(); | |
this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::MoveFocusRequest( | |
const double* p1, const double* p2, const double currPos[2], double center[3]) | |
{ | |
const bool SmoothMotion = true; | |
if (SmoothMotion) | |
{ | |
double focus[4], v[3] = { 0, 0, 0 }; | |
// Returns vtkCoordinate corresponding to the world position | |
focus[0] = this->WorldPosition[0]; | |
focus[1] = this->WorldPosition[1]; | |
focus[2] = this->WorldPosition[2]; | |
v[0] = p2[0] - p1[0]; | |
v[1] = p2[1] - p1[1]; | |
v[2] = p2[2] - p1[2]; | |
focus[0] += v[0]; | |
focus[1] += v[1]; | |
focus[2] += v[2]; | |
focus[3] = 1.0; | |
// Get the display position that this center would fall on. | |
this->CurrentRenderer->SetWorldPoint(focus); | |
this->CurrentRenderer->WorldToDisplay(); | |
this->CurrentRenderer->GetDisplayPoint(center); | |
} | |
else | |
{ | |
center[0] = currPos[0]; | |
center[1] = currPos[1]; | |
center[2] = 1.0; | |
} | |
} | |
void vtkImplicitRectangleWidget::UpdateCamera() | |
{ | |
// Overload this in descendants | |
} | |
void vtkImplicitRectangleWidget::OnMouseMove() | |
{ | |
// See whether we're active | |
if (this->State == vtkImplicitRectangleWidget::Outside || | |
this->State == vtkImplicitRectangleWidget::Start) | |
{ | |
return; | |
} | |
int X = this->Interactor->GetEventPosition()[0]; | |
int Y = this->Interactor->GetEventPosition()[1]; | |
// Do different things depending on state | |
vtkCamera* camera = this->CurrentRenderer->GetActiveCamera(); | |
if (!camera) | |
{ | |
return; | |
} | |
// Calculations everybody does | |
double focalPoint[4], pickPoint[4], prevPickPoint[4]; | |
double z, vpn[3]; | |
// Compute the two points defining the motion vector | |
this->ComputeWorldToDisplay( | |
this->LastPickPosition[0], this->LastPickPosition[1], this->LastPickPosition[2], focalPoint); | |
z = focalPoint[2]; | |
// Z-coordinate is world-coordinate depth of picked object | |
this->ComputeDisplayToWorld(double(this->Interactor->GetLastEventPosition()[0]), | |
double(this->Interactor->GetLastEventPosition()[1]), z, prevPickPoint); | |
this->ComputeDisplayToWorld(double(X), double(Y), z, pickPoint); | |
// Process the motion | |
if (this->State == vtkImplicitRectangleWidget::MovingOnSurface) | |
{ | |
vtkDebugMacro(<< "MovingOnSurface"); | |
double eventPos[2] = { static_cast<double>(X), static_cast<double>(Y) }; | |
// Taken from vtkAbstractPolygonalHandleRepresentation::WidgetInteraction | |
double startPickPoint[4]; | |
this->ComputeDisplayToWorld( | |
this->StartEventPosition[0], this->StartEventPosition[1], z, startPickPoint); | |
double newCenterPointRequested[3]; // displayPosition | |
double newCenterPoint[3], worldOrient[9]; | |
this->WorldPosition[0] = pickPoint[0]; | |
this->WorldPosition[1] = pickPoint[1]; | |
this->WorldPosition[2] = pickPoint[2]; | |
this->WorldPosition[0] = prevPickPoint[0]; | |
this->WorldPosition[1] = prevPickPoint[1]; | |
this->WorldPosition[2] = prevPickPoint[2]; | |
// displayPos is output from MoveFocusRequest | |
this->MoveFocusRequest(prevPickPoint, pickPoint, eventPos, newCenterPointRequested); | |
// See what the placer has to say | |
if (this->PointPlacer) | |
{ | |
// See what the placer says. | |
if (this->PointPlacer->ComputeWorldPosition( | |
this->CurrentRenderer, newCenterPointRequested, newCenterPoint, worldOrient)) | |
{ | |
// Actually, a new origin | |
double newCenter[3]{}; | |
this->UserTransform->TransformPoint(this->Origin, newCenter); | |
double translation[3]{}; | |
vtkMath::Subtract(newCenterPoint, newCenter, translation); | |
// Once the placer has validated us, update the handle position | |
this->UserTransform->PostMultiply(); | |
this->UserTransform->Translate(translation[0], translation[1], translation[2]); | |
this->UserTransform->PreMultiply(); | |
} | |
} | |
} | |
else if (this->State == vtkImplicitRectangleWidget::Moving) | |
{ | |
vtkDebugMacro(<< "Moving"); | |
// Consider to check if handle is active and CTRL | |
this->Translate(prevPickPoint, pickPoint); | |
} | |
else if (this->State == vtkImplicitRectangleWidget::Scaling) | |
{ | |
vtkDebugMacro(<< "Scaling"); | |
this->Scale(prevPickPoint, pickPoint, X, Y); | |
} | |
else if (this->State == vtkImplicitRectangleWidget::Pushing) | |
{ | |
vtkDebugMacro(<< "Pushing"); | |
this->Push(prevPickPoint, pickPoint); | |
} | |
else if (this->State == vtkImplicitRectangleWidget::Rotating) | |
{ | |
vtkDebugMacro(<< "Rotating"); | |
camera->GetViewPlaneNormal(vpn); | |
this->Rotate(X, Y, prevPickPoint, pickPoint, vpn); | |
} | |
else if (this->State == vtkImplicitRectangleWidget::SpinningAxis || | |
this->State == vtkImplicitRectangleWidget::Spinning) | |
{ | |
// Rotate in sector plane around center | |
double spinAxis[3] = { 0.0, 0.0, 0.0 }; | |
if (this->State == vtkImplicitRectangleWidget::SpinningAxis) | |
{ | |
vtkDebugMacro(<< "SpinningAxis"); | |
// Spinning around handle or in-plane | |
if (this->CurrentHandle) | |
{ | |
vtkDebugMacro(<< "SPIN AROUND HANDLE"); | |
// Compute spin axis. Here center must be different from origin | |
vtkMath::Subtract(this->Center, this->Origin, spinAxis); | |
vtkMath::Normalize(spinAxis); | |
} | |
else | |
{ | |
// Not implemented - was used for spinning in another plane. | |
vtkDebugMacro(<< "SPIN IN-PLANE"); | |
// Z-axis - orthogonal to sector | |
spinAxis[2] = 1.0; | |
} | |
} | |
else if (this->State == vtkImplicitRectangleWidget::Spinning) | |
{ | |
vtkDebugMacro(<< "Spinning"); | |
// Spin around 'x-axis' | |
cout << "Spin around x-axis" << endl; | |
double handleAxis[3] = { 0.0, 0.0, 0.0 }; | |
double zAxis[3] = { 0.0, 0.0, 1.0 }; | |
vtkMath::Subtract(this->Center, this->Origin, handleAxis); | |
vtkMath::Normalize(handleAxis); | |
vtkMath::Cross(handleAxis, zAxis, spinAxis); | |
} | |
this->Spin(prevPickPoint, pickPoint, spinAxis); | |
} | |
// Interact, if desired | |
this->UpdateCamera(); | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->InvokeEvent(vtkCommand::InteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::OnStartPinch() | |
{ | |
// We could start interaction for scaling the handles when zooming | |
} | |
void vtkImplicitRectangleWidget::OnPinch() | |
{ | |
if (this->State != vtkImplicitRectangleWidget::Pinching) | |
{ | |
return; | |
} | |
// We do nothing. We could scale the handles - make them smaller | |
// when zooming | |
} | |
void vtkImplicitRectangleWidget::OnEndPinch() | |
{ | |
if (this->State != vtkImplicitRectangleWidget::Pinching) | |
{ | |
return; | |
} | |
this->HighlightHandle(nullptr); | |
this->HighlightRectangle(0); | |
this->SizeHandles(); | |
this->EventCallbackCommand->SetAbortFlag(1); | |
this->EndInteraction(); | |
this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr); | |
this->Interactor->Render(); | |
} | |
void vtkImplicitRectangleWidget::HighlightRectangle(int highlight) | |
{ | |
if (highlight) | |
{ | |
// Store last pick position | |
this->ValidPick = 1; | |
this->PlanePicker->GetPickPosition(this->LastPickPosition); | |
if (this->Interactor->GetControlKey()) | |
{ | |
this->PlaneActor->SetProperty(this->SelectedPlaneCtrlProperty); | |
} | |
else | |
{ | |
this->PlaneActor->SetProperty(this->SelectedPlaneProperty); | |
} | |
} | |
else | |
{ | |
this->PlaneActor->SetProperty(this->PlaneProperty); | |
} | |
} | |
void vtkImplicitRectangleWidget::RegisterPickers() | |
{ | |
vtkPickingManager* pm = this->GetPickingManager(); | |
if (!pm) | |
{ | |
return; | |
} | |
pm->AddPicker(this->HandlePicker, this); | |
} | |
void vtkImplicitRectangleWidget::Rotate(int X, int Y, double* p1, double* p2, double* vpn) | |
{ | |
vtkDebugMacro(<< __FUNCTION__); | |
double v[3]; // vector of motion | |
double axis[3]; // axis of rotation | |
double theta; // rotation angle | |
// mouse motion vector in world space | |
v[0] = p2[0] - p1[0]; | |
v[1] = p2[1] - p1[1]; | |
v[2] = p2[2] - p1[2]; | |
// Create axis of rotation and angle of rotation | |
vtkMath::Cross(vpn, v, axis); | |
if (vtkMath::Normalize(axis) == 0.0) | |
{ | |
vtkDebugMacro(<< "View plane normal parallel to motion vector"); | |
return; | |
} | |
const int* size = this->CurrentRenderer->GetSize(); | |
double l2 = SQUARE(double(X) - this->Interactor->GetLastEventPosition()[0]) + | |
SQUARE(double(Y) - this->Interactor->GetLastEventPosition()[1]); | |
theta = 360.0 * sqrt(l2 / (SQUARE(double(size[0])) + SQUARE(double(size[1])))); | |
// Manipulate the transform to reflect the rotation | |
vtkNew<vtkTransform> transform; | |
transform->Identity(); | |
transform->PostMultiply(); | |
// Works - consider doing this without concatenation!!! | |
double newCenter[3]{}; | |
this->UserTransform->TransformPoint(this->Center, newCenter); | |
transform->Translate(-newCenter[0], -newCenter[1], -newCenter[2]); | |
transform->RotateWXYZ(theta, axis); | |
transform->Translate(newCenter[0], newCenter[1], newCenter[2]); | |
// Update user transform - test | |
this->UserTransform->PostMultiply(); | |
this->UserTransform->Concatenate(transform); | |
this->UserTransform->PreMultiply(); | |
// TODO: We can do this without concatenation | |
this->UserTransform->SetMatrix(this->UserTransform->GetMatrix()); | |
this->UserTransform->Update(); | |
this->PlaneSource->Update(); | |
} | |
void vtkImplicitRectangleWidget::Spin(double* p1, double* p2, double* spinAxis) | |
{ | |
// Mouse motion vector in world space | |
double v[3]; | |
v[0] = p2[0] - p1[0]; | |
v[1] = p2[1] - p1[1]; | |
v[2] = p2[2] - p1[2]; | |
// Current spin axis | |
double axis[3]; | |
double normal[3], position[3]; | |
this->UserTransform->TransformPoint(spinAxis, normal); | |
this->UserTransform->GetPosition(position); | |
vtkMath::Subtract(normal, position, axis); | |
vtkMath::Normalize(axis); // Should not be necessary | |
// Get current center | |
double center[3]; | |
this->UserTransform->TransformPoint(this->Center, center); | |
// Radius vector (from center to cursor position) | |
double rv[3] = { p2[0] - center[0], p2[1] - center[1], p2[2] - center[2] }; | |
// Distance between center and cursor location | |
double rs = vtkMath::Normalize(rv); | |
// Spin direction | |
double ax_cross_rv[3]; | |
vtkMath::Cross(axis, rv, ax_cross_rv); | |
// Spin angle | |
double theta = | |
vtkMath::DegreesFromRadians(vtkMath::Dot(v, ax_cross_rv) / std::max<double>(rs, 1e-6)); | |
// Manipulate the transform to reflect the rotation | |
vtkNew<vtkTransform> transform; | |
// Pre-multiply. Move from origin to original center, rotate and move back | |
transform->Translate(this->Center[0], this->Center[1], this->Center[2]); | |
transform->RotateWXYZ(theta, spinAxis); | |
transform->Translate(-this->Center[0], -this->Center[1], -this->Center[2]); | |
// Update user transform | |
this->UserTransform->Concatenate(transform); | |
this->UserTransform->Update(); | |
// TODO: Do this differently | |
this->UserTransform->SetMatrix(this->UserTransform->GetMatrix()); | |
this->UserTransform->Update(); | |
} | |
void vtkImplicitRectangleWidget::Scale( | |
double* vtkNotUsed(p1), double* vtkNotUsed(p2), int vtkNotUsed(X), int vtkNotUsed(Y)) | |
{ | |
// We do not support scaling | |
} | |
void vtkImplicitRectangleWidget::Translate(double* p1, double* p2) | |
{ | |
vtkDebugMacro(<< __FUNCTION__); | |
// 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]; | |
// We need to move the widget as we see it - hence post multiply | |
vtkNew<vtkTransform> transform; | |
transform->Identity(); | |
transform->PostMultiply(); | |
transform->Translate(v); | |
this->UserTransform->PostMultiply(); | |
this->UserTransform->Concatenate(transform); | |
this->UserTransform->PreMultiply(); | |
// TODO: Do this differently | |
this->UserTransform->SetMatrix(this->UserTransform->GetMatrix()); | |
this->UserTransform->Update(); | |
this->PlaneSource->Update(); // Needed to trigger translation | |
} | |
void vtkImplicitRectangleWidget::Push(double* vtkNotUsed(p1), double* vtkNotUsed(p2)) | |
{ | |
// TODO: Implement function for positioning the handle | |
} | |
void vtkImplicitRectangleWidget::CreateDefaultProperties() | |
{ | |
// Handle properties | |
this->HandleProperty = vtkProperty::New(); | |
this->HandleProperty->SetColor(1, 1, 1); | |
this->SelectedHandleProperty = vtkProperty::New(); | |
this->SelectedHandleProperty->SetColor(1, 0, 0); | |
this->SelectedHandleCtrlProperty = vtkProperty::New(); | |
this->SelectedHandleCtrlProperty->SetColor(0, 0, 1); | |
// Plane properties | |
this->PlaneProperty = vtkProperty::New(); | |
this->PlaneProperty->SetAmbient(1.0); | |
this->PlaneProperty->SetAmbientColor(1.0, 1.0, 1.0); | |
this->PlaneProperty->SetOpacity(0.7); | |
this->SelectedPlaneProperty = vtkProperty::New(); | |
this->SelectedPlaneProperty->SetAmbient(1.0); | |
this->SelectedPlaneProperty->SetAmbientColor(0.0, 1.0, 0.0); | |
this->SelectedPlaneProperty->SetOpacity(0.9); | |
this->SelectedPlaneCtrlProperty = vtkProperty::New(); | |
this->SelectedPlaneCtrlProperty->SetAmbient(1.0); | |
this->SelectedPlaneCtrlProperty->SetAmbientColor(0.0, 0.0, 1.0); | |
this->CubeProperty = vtkProperty::New(); | |
this->CubeProperty->SetAmbient(1.0); | |
this->CubeProperty->SetAmbientColor(1.0, 1.0, 1.0); | |
this->CubeProperty->SetOpacity(0.3); | |
vtkProperty* props1[3] = { this->PlaneProperty, this->SelectedPlaneProperty, | |
this->SelectedPlaneCtrlProperty }; | |
for (int i = 0; i < 3; i++) | |
{ | |
props1[i]->SetEdgeVisibility(1); | |
props1[i]->SetPointSize(3); | |
props1[i]->SetLineWidth(2); | |
props1[i]->SetRenderLinesAsTubes(1); | |
} | |
this->PolyHandleProperty = vtkProperty::New(); | |
this->SelectedPolyHandleProperty = vtkProperty::New(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment