Skip to content
Snippets Groups Projects
Commit 1e2e8d17 authored by Léon Victor's avatar Léon Victor Committed by Kitware Robot
Browse files

Merge topic 'annulus-widget'


221959a1 Implicit Annulus Widget: Add a test
660f3a49 Implicit Annulus: Representation and widget
564a4633 Implicit Annulus Widget: Introduce annulus implicit function

Acked-by: default avatarKitware Robot <kwrobot@kitware.com>
Tested-by: default avatarbuildbot <buildbot@kitware.com>
Reviewed-by: default avatarNicolas Vuaille <nicolas.vuaille@kitware.com>
Reviewed-by: default avatarLucas Givord <lucas.givord@kitware.com>
Merge-request: !11424
parents f320afc4 221959a1
No related branches found
No related tags found
No related merge requests found
Showing
with 3477 additions and 0 deletions
......@@ -10,6 +10,7 @@ set(classes
vtkAnimationScene
vtkAnnotation
vtkAnnotationLayers
vtkAnnulus
vtkArrayData
vtkAtom
vtkAttributesErrorMetric
......
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkAnnulus.h"
#include "vtkCylinder.h"
#include "vtkImplicitBoolean.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkTransform.h"
#include "vtkVector.h"
#include <cmath>
#include <limits>
VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkAnnulus);
//------------------------------------------------------------------------------
vtkAnnulus::vtkAnnulus()
{
this->InnerCylinder->SetRadius(0.25);
this->OuterCylinder->SetRadius(0.5);
this->BooleanOp->AddFunction(this->OuterCylinder);
this->BooleanOp->AddFunction(this->InnerCylinder);
this->BooleanOp->SetOperationTypeToDifference();
}
//------------------------------------------------------------------------------
vtkAnnulus::~vtkAnnulus() = default;
//------------------------------------------------------------------------------
double vtkAnnulus::EvaluateFunction(double x[3])
{
return this->BooleanOp->EvaluateFunction(x);
}
//------------------------------------------------------------------------------
void vtkAnnulus::EvaluateGradient(double x[3], double g[3])
{
return this->BooleanOp->EvaluateGradient(x, g);
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetCenter(double x, double y, double z)
{
this->SetCenter(vtkVector3d(x, y, z));
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetCenter(const double xyz[3])
{
this->SetCenter(vtkVector3d(xyz));
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetCenter(const vtkVector3d& xyz)
{
if (this->Center != xyz)
{
this->Center = xyz;
this->UpdateTransform();
}
}
//------------------------------------------------------------------------------
void vtkAnnulus::GetCenter(double& x, double& y, double& z)
{
x = this->Center[0];
y = this->Center[1];
z = this->Center[2];
}
//------------------------------------------------------------------------------
void vtkAnnulus::GetCenter(double xyz[3])
{
xyz[0] = this->Center[0];
xyz[1] = this->Center[1];
xyz[2] = this->Center[2];
}
//------------------------------------------------------------------------------
double* vtkAnnulus::GetCenter()
{
return this->Center.GetData();
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetAxis(double x, double y, double z)
{
this->SetAxis(vtkVector3d(x, y, z));
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetAxis(double axis[3])
{
this->SetAxis(vtkVector3d(axis));
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetAxis(const vtkVector3d& axis)
{
vtkVector3d newAxis = axis;
// Normalize axis, reject if length == 0
if (newAxis.Normalize() < std::numeric_limits<double>::epsilon())
{
return;
}
if (this->Axis != newAxis)
{
this->Axis = newAxis;
this->UpdateTransform();
}
}
//------------------------------------------------------------------------------
void vtkAnnulus::GetAxis(double& x, double& y, double& z)
{
x = this->Axis[0];
y = this->Axis[1];
z = this->Axis[2];
}
//------------------------------------------------------------------------------
void vtkAnnulus::GetAxis(double xyz[3])
{
xyz[0] = this->Axis[0];
xyz[1] = this->Axis[1];
xyz[2] = this->Axis[2];
}
//------------------------------------------------------------------------------
double* vtkAnnulus::GetAxis()
{
return this->Axis.GetData();
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetOuterRadius(double radius)
{
if (this->OuterCylinder->GetRadius() != radius)
{
this->OuterCylinder->SetRadius(radius);
this->Modified();
}
}
//------------------------------------------------------------------------------
double vtkAnnulus::GetOuterRadius() const
{
return this->OuterCylinder->GetRadius();
}
//------------------------------------------------------------------------------
void vtkAnnulus::SetInnerRadius(double radius)
{
if (this->InnerCylinder->GetRadius() != radius)
{
this->InnerCylinder->SetRadius(radius);
this->Modified();
}
}
//------------------------------------------------------------------------------
double vtkAnnulus::GetInnerRadius() const
{
return this->InnerCylinder->GetRadius();
}
//------------------------------------------------------------------------------
void vtkAnnulus::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
os << indent << "Center: " << this->Center << std::endl;
os << indent << "Axis: " << this->Axis << std::endl;
os << indent << "Inner Radius: " << this->InnerCylinder->GetRadius() << std::endl;
os << indent << "Outer Radius: " << this->OuterCylinder->GetRadius() << std::endl;
}
//------------------------------------------------------------------------------
void vtkAnnulus::UpdateTransform()
{
const vtkVector3d yAxis(0., 1., 0.);
vtkVector3d cross = yAxis.Cross(this->Axis);
const double crossNorm = cross.Normalize();
const double dot = yAxis.Dot(this->Axis);
const double angle = vtkMath::DegreesFromRadians(std::atan2(crossNorm, dot));
vtkNew<vtkTransform> transform;
transform->Identity();
transform->Translate(this->Center.GetData());
transform->RotateWXYZ(angle, cross.GetData());
transform->Inverse();
this->SetTransform(transform.GetPointer());
this->Modified();
}
VTK_ABI_NAMESPACE_END
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
* @class vtkAnnulus
* @brief implicit function for a annulus
*
* vtkAnnulus computes the implicit function and function gradient
* for an annulus composed of two co-axial cylinders. vtkAnnulus is a concrete
* implementation of vtkImplicitFunction. By default the Annulus is
* centered at the origin and the axis of rotation is along the
* y-axis. You can redefine the center and axis of rotation by setting
* the Center and Axis data members. (Note that it is also possible to
* use the superclass' vtkImplicitFunction transformation matrix if
* necessary to reposition by using FunctionValue() and
* FunctionGradient().)
*
* @warning
* The annulus is infinite in extent. To truncate the annulus in
* modeling operations use the vtkImplicitBoolean in combination with
* clipping planes.
*
*/
#ifndef vtkAnnulus_h
#define vtkAnnulus_h
#include "vtkCommonDataModelModule.h" // For export macro
#include "vtkImplicitFunction.h"
#include "vtkNew.h" // For vtkNew
#include "vtkVector.h" // For vtkVector3d
VTK_ABI_NAMESPACE_BEGIN
class vtkCylinder;
class vtkImplicitBoolean;
class VTKCOMMONDATAMODEL_EXPORT vtkAnnulus : public vtkImplicitFunction
{
public:
static vtkAnnulus* New();
vtkTypeMacro(vtkAnnulus, vtkImplicitFunction);
void PrintSelf(ostream& os, vtkIndent indent) override;
///@{
/**
* Evaluate annulus equation.
*/
using vtkImplicitFunction::EvaluateFunction;
double EvaluateFunction(double x[3]) override;
///@}
/**
* Evaluate annulus function gradient.
*/
void EvaluateGradient(double x[3], double g[3]) override;
///@{
/**
* Set/Get the inner annulus radius. Default is 0.25.
*/
void SetInnerRadius(double radius);
double GetInnerRadius() const;
///@}
///@{
/**
* Set/Get the outer annulus radius. Default is 0.5.
*/
void SetOuterRadius(double radius);
double GetOuterRadius() const;
///@}
///@{
/**
* Set/Get the annulus center. Default is (0, 0, 0).
*/
void SetCenter(double x, double y, double z);
void SetCenter(const double xyz[3]);
void SetCenter(const vtkVector3d& xyz);
void GetCenter(double& x, double& y, double& z);
void GetCenter(double xyz[3]);
double* GetCenter() VTK_SIZEHINT(3);
///@}
///@{
/**
* Set/Get the axis of the annulus. If the axis is not specified as
* a unit vector, it will be normalized. If zero-length axis vector
* is used as input to this method, it will be ignored.
* Default is the Y-axis (0, 1, 0)
*/
void SetAxis(double x, double y, double z);
void SetAxis(double axis[3]);
void SetAxis(const vtkVector3d& axis);
void GetAxis(double& x, double& y, double& z);
void GetAxis(double xyz[3]);
double* GetAxis() VTK_SIZEHINT(3);
///@}
protected:
vtkAnnulus();
~vtkAnnulus() override;
private:
vtkAnnulus(const vtkAnnulus&) = delete;
void operator=(const vtkAnnulus&) = delete;
void UpdateTransform();
vtkVector3d Center = { 0.0, 0.0, 0.0 };
vtkVector3d Axis = { 0.0, 1.0, 0.0 };
vtkNew<vtkCylinder> InnerCylinder;
vtkNew<vtkCylinder> OuterCylinder;
vtkNew<vtkImplicitBoolean> BooleanOp;
};
VTK_ABI_NAMESPACE_END
#endif
# Introduce implicit Annulus
The new `vtkAnnulus` implicit function represents an infinite annulus (two co-axial cylinders). It exposes getters and setters for its axis, origin, and inner/outer radii parameters. Changing those will automatically update the base `vtkImplicitFunction`'s transform.
# Add a new Implicit Annulus Widget
The new `vtkAnnulus` has a widget representation. The representation can be manipulated through widget controls:
- Rotate through the axis handle
- Translate through the center handle
- Scale through the outline handle
- Adjust inner/outer radii through the cone edges handles
Its underlying annulus can be used in any filter relying on implicit functions (i.e. Clip, Slice).
......@@ -80,6 +80,8 @@ set(classes
vtkImageOrthoPlanes
vtkImagePlaneWidget
vtkImageTracerWidget
vtkImplicitAnnulusRepresentation
vtkImplicitAnnulusWidget
vtkImplicitConeRepresentation
vtkImplicitConeWidget
vtkImplicitCylinderRepresentation
......
......@@ -34,6 +34,7 @@ vtk_add_test_cxx(vtkInteractionWidgetsCxxTests tests
TestHandleWidget.cxx
TestHandleWidget2D.cxx
TestImageActorContourWidget.cxx
TestImplicitAnnulusWidget.cxx
TestImplicitConeWidget.cxx
TestImplicitCylinderWidget.cxx
TestImplicitCylinderWidget2.cxx
......
This diff is collapsed.
d08529a11ab5a873120a9a09b93708821b54b315160f969fb98a78f63bea656556425efd311a583de35989350866f70f4c52d594dae3983f3c7ac30a65551613
This diff is collapsed.
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
* @class vtkImplicitAnnulusRepresentation
* @brief defining the representation for a vtkImplicitAnnulusWidget
*
* This class is a concrete representation for the
* vtkImplicitAnnulusWidget. It represents an infinite annulus
* defined by its inner/outer radiuses, its center, and its axis. The annulus is placed
* within its associated bounding box and the intersection of the
* annulus with the bounding box is shown to visually indicate the
* orientation and position of the representation. This annulus
* representation can be manipulated by using the
* vtkImplicitAnnulusWidget to adjust the annulus angle, axis,
* and/or center point. (Note that the bounding box is defined during
* invocation of the superclass' PlaceWidget() method.)
*
* To use this representation, you normally specify inner and outer radii, center,
* and axis, and a resolution for the annulus. Finally, place the widget and
* its representation in the scene using PlaceWidget().
*
* @sa
* vtkImplicitAnnulusWidget vtkAnnulus
*/
#ifndef vtkImplicitAnnulusRepresentation_h
#define vtkImplicitAnnulusRepresentation_h
#include "vtkInteractionWidgetsModule.h" // For export macro
#include "vtkVector.h" // For vtkVector3d
#include "vtkWidgetRepresentation.h"
#include "vtkWrappingHints.h" // For VTK_MARSHALAUTO
VTK_ABI_NAMESPACE_BEGIN
class vtkActor;
class vtkPolyDataMapper;
class vtkConeSource;
class vtkLineSource;
class vtkSphereSource;
class vtkTubeFilter;
class vtkAnnulus;
class vtkProperty;
class vtkImageData;
class vtkOutlineFilter;
class vtkPolyData;
class vtkBox;
class vtkCellPicker;
#define VTK_MAX_ANNULUS_RESOLUTION 2048
class VTKINTERACTIONWIDGETS_EXPORT VTK_MARSHALAUTO vtkImplicitAnnulusRepresentation
: public vtkWidgetRepresentation
{
public:
// Manage the state of the widget
enum InteractionStateType
{
Outside = 0,
Moving, // Generic state set by the widget
MovingOutline,
MovingCenter,
RotatingAxis,
AdjustingInnerRadius,
AdjustingOuterRadius,
Scaling,
TranslatingCenter
};
static vtkImplicitAnnulusRepresentation* New();
vtkTypeMacro(vtkImplicitAnnulusRepresentation, vtkWidgetRepresentation);
void PrintSelf(ostream& os, vtkIndent indent) override;
///@{
/**
* Get the center of the annulus representation. The center is located along the
* annulus axis.
* Default is (0, 0, 0)
*/
void SetCenter(double x, double y, double z);
void SetCenter(double x[3]);
double* GetCenter() const VTK_SIZEHINT(3);
void GetCenter(double xyz[3]) const;
///@}
///@{
/**
* Set/Get the axis of rotation for the annulus. If the axis is not
* specified as a unit vector, it will be normalized.
* Default is the Y-Axis (0, 1, 0)
*/
void SetAxis(double x, double y, double z);
void SetAxis(double a[3]);
double* GetAxis() const VTK_SIZEHINT(3);
void GetAxis(double a[3]) const;
///@}
///@{
/**
* Set/Get the annulus inner radius. Values will be clamped between 0 and the outer radius.
* Default is 0.25.
*/
void SetInnerRadius(double r);
double GetInnerRadius() const;
///@}
///@{
/**
* Set/Get the annulus outer radius. Values lower than the inner radius will be clamped.
* Default is 0.5.
*/
void SetOuterRadius(double r);
double GetOuterRadius() const;
///@}
///@{
/**
* Force the annulus widget to be aligned with one of the x-y-z axes.
* If one axis is set on, the other two will be set off.
* Remember that when the state changes, a ModifiedEvent is invoked.
* This can be used to snap the annulus to the axes if it is centerally
* not aligned.
* Default to false.
*/
void SetAlongXAxis(bool);
vtkGetMacro(AlongXAxis, bool);
vtkBooleanMacro(AlongXAxis, bool);
void SetAlongYAxis(bool);
vtkGetMacro(AlongYAxis, bool);
vtkBooleanMacro(AlongYAxis, bool);
void SetAlongZAxis(bool);
vtkGetMacro(AlongZAxis, bool);
vtkBooleanMacro(AlongZAxis, bool);
///@}
///@{
/**
* Enable/disable the drawing of the annulus. In some cases the annulus
* interferes with the object that it is operating on (e.g., the
* annulus interferes with the cut surface it produces resulting in
* z-buffer artifacts.) By default it is off.
*/
void SetDrawAnnulus(bool draw);
vtkGetMacro(DrawAnnulus, bool);
vtkBooleanMacro(DrawAnnulus, bool);
///@}
///@{
/**
* Set/Get the resolution of the annulus. This is the number of
* polygonal facets used to approximate the
* surface (for rendering purposes). A vtkAnnulus is used under
* the hood to provide an exact surface representation.
* Defaults to 128.
*/
vtkSetClampMacro(Resolution, int, 8, VTK_MAX_ANNULUS_RESOLUTION);
vtkGetMacro(Resolution, int);
///@}
///@{
/**
* Turn on/off tubing of the wire outline of the annulus
* intersection (against the bounding box). The tube thickens the
* line by wrapping with a vtkTubeFilter.
* Defaults to true.
*/
vtkSetMacro(Tubing, bool);
vtkGetMacro(Tubing, bool);
vtkBooleanMacro(Tubing, bool);
///@}
///@{
/**
* Turn on/off the ability to translate the bounding box by moving it
* with the mouse.
* Defaults to true.
*/
vtkSetMacro(OutlineTranslation, bool);
vtkGetMacro(OutlineTranslation, bool);
vtkBooleanMacro(OutlineTranslation, bool);
///@}
///@{
/**
* Turn on/off the ability to move the widget outside of the bounds
* specified in the PlaceWidget() invocation.
* Defaults to true.
*/
vtkSetMacro(OutsideBounds, bool);
vtkGetMacro(OutsideBounds, bool);
vtkBooleanMacro(OutsideBounds, bool);
///@}
///@{
/**
* Set/Get the bounds of the widget representation. PlaceWidget can also be
* used to set the bounds of the widget but it may also have other effects
* on the internal state of the representation. Use this function when only
* the widget bounds need to be modified.
*/
vtkSetVector6Macro(WidgetBounds, double);
double* GetWidgetBounds();
///@}
///@{
/**
* Turn on/off whether the annulus should be constrained to the widget bounds.
* If on, the center will not be allowed to move outside the set widget bounds.
* This is the default behaviour.
* If off, the center can be freely moved. The widget outline will change accordingly.
* Defaults to true.
*/
vtkSetMacro(ConstrainToWidgetBounds, bool);
vtkGetMacro(ConstrainToWidgetBounds, bool);
vtkBooleanMacro(ConstrainToWidgetBounds, bool);
///@}
///@{
/**
* Turn on/off the ability to scale the widget with the mouse.
* Defaults to true.
*/
vtkSetMacro(ScaleEnabled, bool);
vtkGetMacro(ScaleEnabled, bool);
vtkBooleanMacro(ScaleEnabled, bool);
///@}
/**
* Grab the polydata that defines the annulus. The polydata contains
* polygons that are clipped by the bounding box.
*/
void GetPolyData(vtkPolyData* pd);
/**
* Satisfies the superclass API. This will change the state of the widget
* to match changes that have been made to the underlying PolyDataSource.
*/
void UpdatePlacement();
///@{
/**
* Get the properties on the axis (line and annulus).
*/
vtkGetObjectMacro(AxisProperty, vtkProperty);
vtkGetObjectMacro(SelectedAxisProperty, vtkProperty);
///@}
///@{
/**
* Get the annulus properties. The properties of the annulus when selected
* and unselected can be manipulated.
*/
vtkGetObjectMacro(AnnulusProperty, vtkProperty);
vtkGetObjectMacro(SelectedAnnulusProperty, vtkProperty);
///@}
///@{
/**
* Get the annulus radii properties. The properties of the annulus inner and outer radii when
* selected and unselected can be manipulated.
*/
vtkGetObjectMacro(RadiusHandleProperty, vtkProperty);
vtkGetObjectMacro(SelectedRadiusHandleProperty, vtkProperty);
///@}
///@{
/**
* Get the property of the outline.
*/
vtkGetObjectMacro(OutlineProperty, vtkProperty);
vtkGetObjectMacro(SelectedOutlineProperty, vtkProperty);
///@}
///@{
/**
* Set the color of all the widgets handles (edges, axis, selected annulus)
* and their color during interaction. Foreground color applies to the outlines and unselected
* annulus.
*/
void SetInteractionColor(double, double, double);
void SetInteractionColor(double c[3]) { this->SetInteractionColor(c[0], c[1], c[2]); }
void SetHandleColor(double, double, double);
void SetHandleColor(double c[3]) { this->SetHandleColor(c[0], c[1], c[2]); }
void SetForegroundColor(double, double, double);
void SetForegroundColor(double c[3]) { this->SetForegroundColor(c[0], c[1], c[2]); }
///@}
///@{
/**
* Methods to interface with the vtkImplicitAnnulusWidget.
*/
int ComputeInteractionState(int X, int Y, int modify = 0) override;
void PlaceWidget(double bounds[6]) override;
void BuildRepresentation() override;
void StartWidgetInteraction(double eventPos[2]) override;
void WidgetInteraction(double newEventPos[2]) override;
void EndWidgetInteraction(double newEventPos[2]) override;
///@}
///@{
/**
* Methods supporting the rendering process.
*/
double* GetBounds() override;
void GetActors(vtkPropCollection* pc) override;
void ReleaseGraphicsResources(vtkWindow*) override;
int RenderOpaqueGeometry(vtkViewport*) override;
int RenderTranslucentPolygonalGeometry(vtkViewport*) override;
vtkTypeBool HasTranslucentPolygonalGeometry() override;
///@}
///@{
/**
* Specify a translation distance used by the BumpAnnulus() method. Note that the
* distance is normalized; it is the fraction of the length of the bounding
* box of the wire outline.
* Defaults to 0.01.
*/
vtkSetClampMacro(BumpDistance, double, 0.000001, 1);
vtkGetMacro(BumpDistance, double);
///@}
/**
* Translate the annulus in the direction of the view vector by the
* specified BumpDistance. The dir parameter controls which
* direction the pushing occurs, either in the same direction as the
* view vector, or when negative, in the opposite direction. The factor
* controls what percentage of the bump is used.
*/
void BumpAnnulus(int dir, double factor);
/**
* Push the annulus the distance specified along the view
* vector. Positive values are in the direction of the view vector;
* negative values are in the opposite direction. The distance value
* is expressed in world coordinates.
*/
void PushAnnulus(double distance);
/**
* The interaction state may be set from a widget (e.g.,
* vtkImplicitAnnulusWidget) or other object. This controls how the
* interaction with the widget proceeds. Normally this method is used as
* part of a handshaking process with the widget: First
* ComputeInteractionState() is invoked that returns a state based on
* geometric considerations (i.e., cursor near a widget feature), then
* based on events, the widget may modify this further.
*/
vtkSetClampMacro(InteractionState, InteractionStateType, InteractionStateType::Outside,
InteractionStateType::TranslatingCenter);
///@{
/**
* Sets the visual appearance of the representation based on the
* state it is in. This state is usually the same as InteractionState.
*/
virtual void SetRepresentationState(InteractionStateType);
vtkGetMacro(RepresentationState, InteractionStateType);
///@}
/*
* Register internal Pickers within PickingManager
*/
void RegisterPickers() override;
///@{
/**
* Gets/Sets the constraint axis for translations.
* Defaults to Axis::NONE
**/
vtkGetMacro(TranslationAxis, int);
vtkSetClampMacro(TranslationAxis, int, Axis::NONE, Axis::ZAxis);
///@}
///@{
/**
* Toggles constraint translation axis on/off.
*/
void SetXTranslationAxisOn() { this->TranslationAxis = Axis::XAxis; }
void SetYTranslationAxisOn() { this->TranslationAxis = Axis::YAxis; }
void SetZTranslationAxisOn() { this->TranslationAxis = Axis::ZAxis; }
void SetTranslationAxisOff() { this->TranslationAxis = Axis::NONE; }
///@}
/**
* Returns true if ConstrainedAxis
**/
bool IsTranslationConstrained() { return this->TranslationAxis != Axis::NONE; }
void GetAnnulus(vtkAnnulus* annulus) const;
protected:
vtkImplicitAnnulusRepresentation();
~vtkImplicitAnnulusRepresentation() override;
private:
struct AxisHandleRepresentation
{
vtkNew<vtkLineSource> LineSource;
vtkNew<vtkPolyDataMapper> LineMapper;
vtkNew<vtkActor> LineActor;
vtkNew<vtkConeSource> ArrowSource;
vtkNew<vtkPolyDataMapper> ArrowMapper;
vtkNew<vtkActor> ArrowActor;
};
struct RadiusHandleRepresentation
{
vtkNew<vtkPolyData> PolyData;
vtkNew<vtkTubeFilter> Tuber;
vtkNew<vtkPolyDataMapper> Mapper;
vtkNew<vtkActor> Actor;
};
vtkImplicitAnnulusRepresentation(const vtkImplicitAnnulusRepresentation&) = delete;
void operator=(const vtkImplicitAnnulusRepresentation&) = delete;
void HighlightAnnulus(bool highlight);
void HighlightCenterHandle(bool highlight);
void HighlightAxis(bool highlight);
void HighlightOutline(bool highlight);
void HighlightInnerRadiusHandle(bool highlight);
void HighlightOuterRadiusHandle(bool highlight);
// Methods to manipulate the annulus
void Rotate(
double X, double Y, const vtkVector3d& p1, const vtkVector3d& p2, const vtkVector3d& vpn);
void TranslateAnnulus(const vtkVector3d& p1, const vtkVector3d& p2);
void TranslateOutline(const vtkVector3d& p1, const vtkVector3d& p2);
void TranslateCenter(const vtkVector3d& p1, const vtkVector3d& p2);
void TranslateCenterOnAxis(const vtkVector3d& p1, const vtkVector3d& p2);
void ScaleRadii(const vtkVector3d& p1, const vtkVector3d& p2);
void AdjustOuterRadius(double X, double Y, const vtkVector3d& p1, const vtkVector3d& p2);
void AdjustInnerRadius(double X, double Y, const vtkVector3d& p1, const vtkVector3d& p2);
void Scale(const vtkVector3d& p1, const vtkVector3d& p2, double X, double Y);
void SizeHandles();
// Generate the annulus polydata, cropped by the bounding box
void BuildAnnulus();
// The actual annulus we're manipulating
vtkNew<vtkAnnulus> Annulus;
InteractionStateType RepresentationState = InteractionStateType::Outside;
int TranslationAxis = Axis::NONE;
// Keep track of event positions
vtkVector3d LastEventPosition;
// Controlling the push operation
double BumpDistance = 0.01;
// Controlling ivars
bool AlongXAxis = false;
bool AlongYAxis = false;
bool AlongZAxis = false;
// The facet resolution for rendering purposes.
int Resolution = 128;
// The bounding box is represented by a single voxel image data
vtkNew<vtkImageData> Box;
vtkNew<vtkOutlineFilter> Outline;
vtkNew<vtkPolyDataMapper> OutlineMapper;
vtkNew<vtkActor> OutlineActor;
bool OutlineTranslation = true; // whether the outline can be moved
bool ScaleEnabled = true; // whether the widget can be scaled
bool OutsideBounds = true; // whether the widget can be moved outside input's bounds
vtkVector<double, 6> WidgetBounds;
bool ConstrainToWidgetBounds = true;
vtkNew<vtkPolyData> AnnulusPD;
vtkNew<vtkPolyDataMapper> AnnulusMapper;
vtkNew<vtkActor> AnnulusActor;
bool DrawAnnulus = true;
// Optional tubes are represented by extracting boundary edges and tubing
RadiusHandleRepresentation InnerRadiusRepresentation;
RadiusHandleRepresentation OuterRadiusRepresentation;
bool Tubing = true; // control whether tubing is on
// Axis representations
AxisHandleRepresentation LowerAxisRepresentation;
AxisHandleRepresentation UpperAxisRepresentation;
// Center positioning handle
vtkNew<vtkSphereSource> CenterHandleSource;
vtkNew<vtkPolyDataMapper> CenterHandleMapper;
vtkNew<vtkActor> CenterHandleActor;
// Do the picking
vtkNew<vtkCellPicker> Picker;
vtkNew<vtkCellPicker> AnnulusPicker;
// Properties used to control the appearance of selected objects and
// the manipulator in general.
vtkNew<vtkProperty> AxisProperty;
vtkNew<vtkProperty> SelectedAxisProperty;
vtkNew<vtkProperty> AnnulusProperty;
vtkNew<vtkProperty> SelectedAnnulusProperty;
vtkNew<vtkProperty> OutlineProperty;
vtkNew<vtkProperty> SelectedOutlineProperty;
vtkNew<vtkProperty> RadiusHandleProperty;
vtkNew<vtkProperty> SelectedRadiusHandleProperty;
vtkNew<vtkProperty> CenterHandleProperty;
vtkNew<vtkProperty> SelectedCenterHandleProperty;
vtkNew<vtkBox> BoundingBox;
};
VTK_ABI_NAMESPACE_END
#endif
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkImplicitAnnulusWidget.h"
#include "vtkCallbackCommand.h"
#include "vtkCamera.h"
#include "vtkCommand.h"
#include "vtkEvent.h"
#include "vtkImplicitAnnulusRepresentation.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkWidgetEvent.h"
#include "vtkWidgetEventTranslator.h"
VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkImplicitAnnulusWidget);
namespace
{
constexpr double SPEED_FACTOR_HALF = 0.5;
constexpr double SPEED_FACTOR_FULL = 1.0;
}
//------------------------------------------------------------------------------
vtkImplicitAnnulusWidget::vtkImplicitAnnulusWidget()
{
// Define widget events
// Mouse buttons: Selection
this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkWidgetEvent::Select,
this, vtkImplicitAnnulusWidget::SelectAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent,
vtkWidgetEvent::EndSelect, this, vtkImplicitAnnulusWidget::EndSelectAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::MiddleButtonPressEvent,
vtkWidgetEvent::Translate, this, vtkImplicitAnnulusWidget::TranslateAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::MiddleButtonReleaseEvent,
vtkWidgetEvent::EndTranslate, this, vtkImplicitAnnulusWidget::EndSelectAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonPressEvent, vtkWidgetEvent::Scale,
this, vtkImplicitAnnulusWidget::ScaleAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonReleaseEvent,
vtkWidgetEvent::EndScale, this, vtkImplicitAnnulusWidget::EndSelectAction);
// Mouse motion: Move the annulus around
this->CallbackMapper->SetCallbackMethod(
vtkCommand::MouseMoveEvent, vtkWidgetEvent::Move, this, vtkImplicitAnnulusWidget::MoveAction);
// Arrow keys: Move the annulus around
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 30, 1,
"Up", vtkWidgetEvent::Up, this, vtkImplicitAnnulusWidget::MoveAnnulusAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 28, 1,
"Right", vtkWidgetEvent::Up, this, vtkImplicitAnnulusWidget::MoveAnnulusAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 31, 1,
"Down", vtkWidgetEvent::Down, this, vtkImplicitAnnulusWidget::MoveAnnulusAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 29, 1,
"Left", vtkWidgetEvent::Down, this, vtkImplicitAnnulusWidget::MoveAnnulusAction);
// X Key: Lock/Unlock X Axis
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 'x', 1,
"x", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 24, 1,
"x", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 'X', 1,
"X", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 'x',
1, "x", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 24, 1,
"x", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 'X',
1, "X", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
// Y Key: Lock/Unlock Y Axis
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 'y', 1,
"y", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 25, 1,
"y", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 'Y', 1,
"Y", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 'y',
1, "y", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 25, 1,
"y", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 'Y',
1, "Y", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
// Z Key: Lock/Unlock Z Axis
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 'z', 1,
"z", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 26, 1,
"z", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::AnyModifier, 'Z', 1,
"Z", vtkWidgetEvent::ModifyEvent, this, vtkImplicitAnnulusWidget::TranslationAxisLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 'z',
1, "z", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 26, 1,
"z", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyReleaseEvent, vtkEvent::AnyModifier, 'Z',
1, "Z", vtkWidgetEvent::Reset, this, vtkImplicitAnnulusWidget::TranslationAxisUnLock);
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::SelectAction(vtkAbstractWidget* w)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(w);
vtkImplicitAnnulusRepresentation* repr = self->GetAnnulusRepresentation();
// Get the event position
int X = self->Interactor->GetEventPosition()[0];
int Y = self->Interactor->GetEventPosition()[1];
// We want to update the angle, axis and origin as appropriate
repr->SetInteractionState(vtkImplicitAnnulusRepresentation::InteractionStateType::Moving);
int interactionState = repr->ComputeInteractionState(X, Y);
self->UpdateCursorShape(interactionState);
if (repr->GetInteractionState() == vtkImplicitAnnulusRepresentation::Outside)
{
return;
}
if (self->Interactor->GetControlKey() &&
interactionState == vtkImplicitAnnulusRepresentation::MovingCenter)
{
repr->SetInteractionState(vtkImplicitAnnulusRepresentation::TranslatingCenter);
}
// We are definitely selected
self->GrabFocus(self->EventCallbackCommand);
double eventPos[2] = {
static_cast<double>(X),
static_cast<double>(Y),
};
self->WidgetState = vtkImplicitAnnulusWidget::Active;
repr->StartWidgetInteraction(eventPos);
self->EventCallbackCommand->SetAbortFlag(true);
self->StartInteraction();
self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
self->Render();
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::TranslateAction(vtkAbstractWidget* w)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(w);
vtkImplicitAnnulusRepresentation* repr = self->GetAnnulusRepresentation();
// Get the event position
int X = self->Interactor->GetEventPosition()[0];
int Y = self->Interactor->GetEventPosition()[1];
// We want to compute an orthogonal vector to the plane that has been selected
repr->SetInteractionState(vtkImplicitAnnulusRepresentation::Moving);
int interactionState = repr->ComputeInteractionState(X, Y);
self->UpdateCursorShape(interactionState);
if (repr->GetInteractionState() == vtkImplicitAnnulusRepresentation::Outside)
{
return;
}
// We are definitely selected
self->GrabFocus(self->EventCallbackCommand);
double eventPos[2] = {
static_cast<double>(X),
static_cast<double>(Y),
};
self->WidgetState = vtkImplicitAnnulusWidget::Active;
repr->StartWidgetInteraction(eventPos);
self->EventCallbackCommand->SetAbortFlag(true);
self->StartInteraction();
self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
self->Render();
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::ScaleAction(vtkAbstractWidget* w)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(w);
vtkImplicitAnnulusRepresentation* repr = self->GetAnnulusRepresentation();
// Get the event position
int X = self->Interactor->GetEventPosition()[0];
int Y = self->Interactor->GetEventPosition()[1];
// We want to compute an orthogonal vector to the pane that has been selected
repr->SetInteractionState(vtkImplicitAnnulusRepresentation::Scaling);
int interactionState = repr->ComputeInteractionState(X, Y);
self->UpdateCursorShape(interactionState);
if (repr->GetInteractionState() == vtkImplicitAnnulusRepresentation::Outside)
{
return;
}
// We are definitely selected
self->GrabFocus(self->EventCallbackCommand);
double eventPos[2] = {
static_cast<double>(X),
static_cast<double>(Y),
};
self->WidgetState = vtkImplicitAnnulusWidget::Active;
repr->StartWidgetInteraction(eventPos);
self->EventCallbackCommand->SetAbortFlag(true);
self->StartInteraction();
self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
self->Render();
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::MoveAction(vtkAbstractWidget* w)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(w);
vtkImplicitAnnulusRepresentation* representation = self->GetAnnulusRepresentation();
// Change the cursor shape when the mouse is hovering
// the widget. Unfortunately, this results in a few extra picks
// due to the cell picker. However given that its picking simple geometry
// like the handles/arrows, this should be very quick
int X = self->Interactor->GetEventPosition()[0];
int Y = self->Interactor->GetEventPosition()[1];
bool changed = false;
if (self->ManagesCursor && self->WidgetState != vtkImplicitAnnulusWidget::Active)
{
auto oldState = static_cast<vtkImplicitAnnulusRepresentation::InteractionStateType>(
representation->GetInteractionState());
representation->SetInteractionState(vtkImplicitAnnulusRepresentation::Moving);
auto newState = static_cast<vtkImplicitAnnulusRepresentation::InteractionStateType>(
representation->ComputeInteractionState(X, Y));
changed = self->UpdateCursorShape(newState);
representation->SetInteractionState(oldState);
changed |= newState != oldState;
}
// See whether we're active
if (self->WidgetState == vtkImplicitAnnulusWidget::Idle)
{
if (changed && self->ManagesCursor)
{
self->Render();
}
return;
}
// Okay, adjust the representation
double e[2] = { static_cast<double>(X), static_cast<double>(Y) };
representation->WidgetInteraction(e);
// moving something
self->EventCallbackCommand->SetAbortFlag(true);
self->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
self->Render();
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::EndSelectAction(vtkAbstractWidget* w)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(w);
vtkImplicitAnnulusRepresentation* repr = self->GetAnnulusRepresentation();
if (self->WidgetState != vtkImplicitAnnulusWidget::Active ||
repr->GetInteractionState() == vtkImplicitAnnulusRepresentation::Outside)
{
return;
}
// Return state to not selected
double e[2];
repr->EndWidgetInteraction(e);
self->WidgetState = vtkImplicitAnnulusWidget::Idle;
self->ReleaseFocus();
// Update cursor if managed
self->UpdateCursorShape(repr->GetRepresentationState());
self->EventCallbackCommand->SetAbortFlag(true);
self->EndInteraction();
self->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
self->Render();
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::MoveAnnulusAction(vtkAbstractWidget* w)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(w);
vtkImplicitAnnulusRepresentation* repr = self->GetAnnulusRepresentation();
repr->SetInteractionState(vtkImplicitAnnulusRepresentation::Moving);
int X = self->Interactor->GetEventPosition()[0];
int Y = self->Interactor->GetEventPosition()[1];
repr->ComputeInteractionState(X, Y);
// The cursor must be over part of the widget for these key presses to work
if (repr->GetInteractionState() == vtkImplicitAnnulusRepresentation::Outside)
{
return;
}
// Invoke all of the events associated with moving the annulus
self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
// Move the annulus
double factor = (self->Interactor->GetControlKey() ? SPEED_FACTOR_HALF : SPEED_FACTOR_FULL);
char* cKeySym = self->Interactor->GetKeySym();
std::string keySym = cKeySym != nullptr ? cKeySym : "";
if (keySym == "Down" || keySym == "Left")
{
self->GetAnnulusRepresentation()->BumpAnnulus(-1, factor);
}
else
{
self->GetAnnulusRepresentation()->BumpAnnulus(1, factor);
}
self->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
self->EventCallbackCommand->SetAbortFlag(true);
self->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
self->Render();
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::CreateDefaultRepresentation()
{
if (!this->WidgetRep)
{
this->WidgetRep = vtkImplicitAnnulusRepresentation::New();
}
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::SetRepresentation(vtkImplicitAnnulusRepresentation* rep)
{
this->Superclass::SetWidgetRepresentation(reinterpret_cast<vtkWidgetRepresentation*>(rep));
}
//------------------------------------------------------------------------------
bool vtkImplicitAnnulusWidget::UpdateCursorShape(int state)
{
// So as to change the cursor shape when the mouse is poised over
// the widget.
if (this->ManagesCursor)
{
if (state == vtkImplicitAnnulusRepresentation::Outside)
{
return this->RequestCursorShape(VTK_CURSOR_DEFAULT);
}
else if (state == vtkImplicitAnnulusRepresentation::MovingOutline)
{
return this->RequestCursorShape(VTK_CURSOR_SIZEALL);
}
else
{
return this->RequestCursorShape(VTK_CURSOR_HAND);
}
}
return false;
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::TranslationAxisLock(vtkAbstractWidget* widget)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(widget);
vtkImplicitAnnulusRepresentation* repr = self->GetAnnulusRepresentation();
char* cKeySym = self->Interactor->GetKeySym();
std::string keySym = cKeySym != nullptr ? cKeySym : "";
std::transform(keySym.begin(), keySym.end(), keySym.begin(), ::toupper);
if (keySym == "X")
{
repr->SetXTranslationAxisOn();
}
else if (keySym == "Y")
{
repr->SetYTranslationAxisOn();
}
else if (keySym == "Z")
{
repr->SetZTranslationAxisOn();
}
}
//------------------------------------------------------------------------------
void vtkImplicitAnnulusWidget::TranslationAxisUnLock(vtkAbstractWidget* widget)
{
vtkImplicitAnnulusWidget* self = reinterpret_cast<vtkImplicitAnnulusWidget*>(widget);
self->GetAnnulusRepresentation()->SetTranslationAxisOff();
}
VTK_ABI_NAMESPACE_END
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
* @class vtkImplicitAnnulusWidget
* @brief 3D widget for manipulating an infinite annulus
*
* This 3D widget defines an infinite annulus that can be
* interactively placed in a scene. The widget is assumed to consist
* of four parts: 1) an annulus contained in a 2) bounding box, with an
* 3) annulus axis, which is rooted at an 4) origin point in the bounding
* box. (The representation paired with this widget determines the
* actual geometry of the widget.)
*
* To use this widget, you generally pair it with a vtkImplicitAnnulusRepresentation
* (or a subclass). Various options are available for controlling how the
* representation appears, and how the widget functions.
*
* @par Event Bindings:
* By default, the widget responds to the following VTK events (i.e., it
* watches the vtkRenderWindowInteractor for these events):
*
* If the annulus axis is selected:
* - LeftButtonPressEvent - select axis
* - LeftButtonReleaseEvent - release (end select) axis
* - MouseMoveEvent - orient the axis vector
* If the center point handle is selected:
* - LeftButtonPressEvent - select handle (if on slider)
* - LeftButtonReleaseEvent - release handle (if selected)
* - MouseMoveEvent - move the center point (constrained to plane or on the
* axis if CTRL key is pressed)
* If the outline is selected:
* - LeftButtonPressEvent - select outline
* - LeftButtonReleaseEvent - release outline
* - MouseMoveEvent - move the outline
* If the keypress characters are used
* - 'Down/Left' Move annulus away from viewer
* - 'Up/Right' Move annulus towards viewer
* In all the cases, independent of what is picked, the widget responds to the
* following VTK events:
* - MiddleButtonPressEvent - move the annulus
* - MiddleButtonReleaseEvent - release the annulus
* - RightButtonPressEvent - scale the widget's representation
* - RightButtonReleaseEvent - stop scaling the widget
* - MouseMoveEvent - scale (if right button) or move (if middle button) the widget
*
* Note that the event bindings described above can be changed using this
* class's vtkWidgetEventTranslator. This class translates VTK events
* into the vtkImplicitAnnulusWidget's widget events:
* <pre>
* vtkWidgetEvent::Select -- some part of the widget has been selected
* vtkWidgetEvent::EndSelect -- the selection process has completed
* vtkWidgetEvent::Move -- a request for widget motion has been invoked
* vtkWidgetEvent::Up and vtkWidgetEvent::Down -- MoveAnnulusAction
* </pre>
*
* In turn, when these widget events are processed, the vtkImplicitAnnulusWidget
* invokes the following VTK events on itself (which observers can listen for):
* <pre>
* vtkCommand::StartInteractionEvent (on vtkWidgetEvent::Select)
* vtkCommand::EndInteractionEvent (on vtkWidgetEvent::EndSelect)
* vtkCommand::InteractionEvent (on vtkWidgetEvent::Move)
* </pre>
*
*
* @sa
* vtk3DWidget vtkAnnulusRepresentation vtkAnnulus
*/
#ifndef vtkImplicitAnnulusWidget_h
#define vtkImplicitAnnulusWidget_h
#include "vtkAbstractWidget.h"
#include "vtkInteractionWidgetsModule.h" // For export macro
#include "vtkWrappingHints.h" // For VTK_MARSHALAUTO
VTK_ABI_NAMESPACE_BEGIN
class vtkImplicitAnnulusRepresentation;
class VTKINTERACTIONWIDGETS_EXPORT VTK_MARSHALAUTO vtkImplicitAnnulusWidget
: public vtkAbstractWidget
{
public:
static vtkImplicitAnnulusWidget* New();
vtkTypeMacro(vtkImplicitAnnulusWidget, vtkAbstractWidget);
/**
* Specify an instance of vtkWidgetRepresentation used to represent this
* widget in the scene. Note that the representation is a subclass of vtkProp
* so it can be added to the renderer independent of the widget.
*/
void SetRepresentation(vtkImplicitAnnulusRepresentation* rep);
/**
* Return the representation as a vtkImplicitAnnulusRepresentation.
*/
vtkImplicitAnnulusRepresentation* GetAnnulusRepresentation()
{
return reinterpret_cast<vtkImplicitAnnulusRepresentation*>(this->WidgetRep);
}
/**
* Create the default widget representation if one is not set.
*/
void CreateDefaultRepresentation() override;
private:
enum WidgetStateType
{
Idle = 0,
Active
};
vtkImplicitAnnulusWidget();
~vtkImplicitAnnulusWidget() override = default;
vtkImplicitAnnulusWidget(const vtkImplicitAnnulusWidget&) = delete;
void operator=(const vtkImplicitAnnulusWidget&) = delete;
///@{
/**
* Callbacks for widget events
*/
static void SelectAction(vtkAbstractWidget* widget);
static void TranslateAction(vtkAbstractWidget* widget);
static void ScaleAction(vtkAbstractWidget* widget);
static void EndSelectAction(vtkAbstractWidget* widget);
static void MoveAction(vtkAbstractWidget* widget);
static void MoveAnnulusAction(vtkAbstractWidget* widget);
static void TranslationAxisLock(vtkAbstractWidget* widget);
static void TranslationAxisUnLock(vtkAbstractWidget* widget);
/// @}
/**
* Update the cursor shape based on the interaction state. Returns true
* if the cursor shape requested is different from the existing one.
*/
bool UpdateCursorShape(int interactionState);
// Manage the state of the widget
WidgetStateType WidgetState = vtkImplicitAnnulusWidget::Idle;
};
VTK_ABI_NAMESPACE_END
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment