1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkSplineWidget.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * @class   vtkSplineWidget
17  * @brief   3D widget for manipulating a spline
18  *
19  * This 3D widget defines a spline that can be interactively placed in a
20  * scene. The spline has handles, the number of which can be changed, plus it
21  * can be picked on the spline itself to translate or rotate it in the scene.
22  * A nice feature of the object is that the vtkSplineWidget, like any 3D
23  * widget, will work with the current interactor style. That is, if
24  * vtkSplineWidget does not handle an event, then all other registered
25  * observers (including the interactor style) have an opportunity to process
26  * the event. Otherwise, the vtkSplineWidget will terminate the processing of
27  * the event that it handles.
28  *
29  * To use this object, just invoke SetInteractor() with the argument of the
30  * method a vtkRenderWindowInteractor.  You may also wish to invoke
31  * "PlaceWidget()" to initially position the widget. The interactor will act
32  * normally until the "i" key (for "interactor") is pressed, at which point the
33  * vtkSplineWidget will appear. (See superclass documentation for information
34  * about changing this behavior.) Events that occur outside of the widget
35  * (i.e., no part of the widget is picked) are propagated to any other
36  * registered obsevers (such as the interaction style).  Turn off the widget
37  * by pressing the "i" key again (or invoke the Off() method).
38  *
39  * The button actions and key modifiers are as follows for controlling the
40  * widget:
41  * 1) left button down on and drag one of the spherical handles to change the
42  * shape of the spline: the handles act as "control points".
43  * 2) left button or middle button down on a line segment forming the spline
44  * allows uniform translation of the widget.
45  * 3) ctrl + middle button down on the widget enables spinning of the widget
46  * about its center.
47  * 4) right button down on the widget enables scaling of the widget. By moving
48  * the mouse "up" the render window the spline will be made bigger; by moving
49  * "down" the render window the widget will be made smaller.
50  * 5) ctrl key + right button down on any handle will erase it providing there
51  * will be two or more points remaining to form a spline.
52  * 6) shift key + right button down on any line segment will insert a handle
53  * onto the spline at the cursor position.
54  *
55  * The vtkSplineWidget has several methods that can be used in conjunction with
56  * other VTK objects. The Set/GetResolution() methods control the number of
57  * subdivisions of the spline; the GetPolyData() method can be used to get the
58  * polygonal representation and can be used for things like seeding
59  * streamlines or probing other data sets. Typical usage of the widget is to
60  * make use of the StartInteractionEvent, InteractionEvent, and
61  * EndInteractionEvent events. The InteractionEvent is called on mouse motion;
62  * the other two events are called on button down and button up (either left or
63  * right button).
64  *
65  * Some additional features of this class include the ability to control the
66  * properties of the widget. You can set the properties of the selected and
67  * unselected representations of the spline. For example, you can set the
68  * property for the handles and spline. In addition there are methods to
69  * constrain the spline so that it is aligned with a plane.  Note that a simple
70  * ruler widget can be derived by setting the resolution to 1, the number of
71  * handles to 2, and calling the GetSummedLength method!
72  *
73  * @par Thanks:
74  * Thanks to Dean Inglis for developing and contributing this class.
75  *
76  * @sa
77  * vtk3DWidget vtkBoxWidget vtkLineWidget vtkPointWidget vtkSphereWidget
78  * vtkImagePlaneWidget vtkImplicitPlaneWidget vtkPlaneWidget
79 */
80 
81 #ifndef vtkSplineWidget_h
82 #define vtkSplineWidget_h
83 
84 #include "vtkInteractionWidgetsModule.h" // For export macro
85 #include "vtk3DWidget.h"
86 
87 class vtkActor;
88 class vtkCellPicker;
89 class vtkParametricSpline;
90 class vtkParametricFunctionSource;
91 class vtkPlaneSource;
92 class vtkPoints;
93 class vtkPolyData;
94 class vtkProp;
95 class vtkProperty;
96 class vtkSphereSource;
97 class vtkTransform;
98 
99 #define VTK_PROJECTION_YZ 0
100 #define VTK_PROJECTION_XZ 1
101 #define VTK_PROJECTION_XY 2
102 #define VTK_PROJECTION_OBLIQUE 3
103 
104 class VTKINTERACTIONWIDGETS_EXPORT vtkSplineWidget : public vtk3DWidget
105 {
106 public:
107   /**
108    * Instantiate the object.
109    */
110   static vtkSplineWidget *New();
111 
112   vtkTypeMacro(vtkSplineWidget,vtk3DWidget);
113   void PrintSelf(ostream& os, vtkIndent indent) override;
114 
115   //@{
116   /**
117    * Methods that satisfy the superclass' API.
118    */
119   void SetEnabled(int) override;
120   void PlaceWidget(double bounds[6]) override;
PlaceWidget()121   void PlaceWidget() override
122     {this->Superclass::PlaceWidget();}
PlaceWidget(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax)123   void PlaceWidget(double xmin, double xmax, double ymin, double ymax,
124                    double zmin, double zmax) override
125     {this->Superclass::PlaceWidget(xmin,xmax,ymin,ymax,zmin,zmax);}
126   //@}
127 
128   //@{
129   /**
130    * Force the spline widget to be projected onto one of the orthogonal planes.
131    * Remember that when the state changes, a ModifiedEvent is invoked.
132    * This can be used to snap the spline to the plane if it is originally
133    * not aligned.  The normal in SetProjectionNormal is 0,1,2 for YZ,XZ,XY
134    * planes respectively and 3 for arbitrary oblique planes when the widget
135    * is tied to a vtkPlaneSource.
136    */
137   vtkSetMacro(ProjectToPlane,vtkTypeBool);
138   vtkGetMacro(ProjectToPlane,vtkTypeBool);
139   vtkBooleanMacro(ProjectToPlane,vtkTypeBool);
140   //@}
141 
142   /**
143    * Set up a reference to a vtkPlaneSource that could be from another widget
144    * object, e.g. a vtkPolyDataSourceWidget.
145    */
146   void SetPlaneSource(vtkPlaneSource* plane);
147 
148   vtkSetClampMacro(ProjectionNormal,int,VTK_PROJECTION_YZ,VTK_PROJECTION_OBLIQUE);
149   vtkGetMacro(ProjectionNormal,int);
SetProjectionNormalToXAxes()150   void SetProjectionNormalToXAxes()
151     { this->SetProjectionNormal(0); }
SetProjectionNormalToYAxes()152   void SetProjectionNormalToYAxes()
153     { this->SetProjectionNormal(1); }
SetProjectionNormalToZAxes()154   void SetProjectionNormalToZAxes()
155     { this->SetProjectionNormal(2); }
SetProjectionNormalToOblique()156   void SetProjectionNormalToOblique()
157     { this->SetProjectionNormal(3); }
158 
159   //@{
160   /**
161    * Set the position of spline handles and points in terms of a plane's
162    * position. i.e., if ProjectionNormal is 0, all of the x-coordinate
163    * values of the points are set to position. Any value can be passed (and is
164    * ignored) to update the spline points when Projection normal is set to 3
165    * for arbitrary plane orientations.
166    */
167   void SetProjectionPosition(double position);
168   vtkGetMacro(ProjectionPosition, double);
169   //@}
170 
171   /**
172    * Grab the polydata (including points) that defines the spline.  The
173    * polydata consists of points and line segments numbering Resolution + 1
174    * and Resoltuion, respectively. Points are guaranteed to be up-to-date when
175    * either the InteractionEvent or EndInteraction events are invoked. The
176    * user provides the vtkPolyData and the points and polyline are added to it.
177    */
178   void GetPolyData(vtkPolyData *pd);
179 
180   //@{
181   /**
182    * Set/Get the handle properties (the spheres are the handles). The
183    * properties of the handles when selected and unselected can be manipulated.
184    */
185   virtual void SetHandleProperty(vtkProperty*);
186   vtkGetObjectMacro(HandleProperty, vtkProperty);
187   virtual void SetSelectedHandleProperty(vtkProperty*);
188   vtkGetObjectMacro(SelectedHandleProperty, vtkProperty);
189   //@}
190 
191   //@{
192   /**
193    * Set/Get the line properties. The properties of the line when selected
194    * and unselected can be manipulated.
195    */
196   virtual void SetLineProperty(vtkProperty*);
197   vtkGetObjectMacro(LineProperty, vtkProperty);
198   virtual void SetSelectedLineProperty(vtkProperty*);
199   vtkGetObjectMacro(SelectedLineProperty, vtkProperty);
200   //@}
201 
202   //@{
203   /**
204    * Set/Get the number of handles for this widget.
205    */
206   virtual void SetNumberOfHandles(int npts);
207   vtkGetMacro(NumberOfHandles, int);
208   //@}
209 
210   //@{
211   /**
212    * Set/Get the number of line segments representing the spline for
213    * this widget.
214    */
215   void SetResolution(int resolution);
216   vtkGetMacro(Resolution,int);
217   //@}
218 
219   //@{
220   /**
221    * Set the parametric spline object. Through vtkParametricSpline's API, the
222    * user can supply and configure one of currently two types of spline:
223    * vtkCardinalSpline, vtkKochanekSpline. The widget controls the open
224    * or closed configuration of the spline.
225    * WARNING: The widget does not enforce internal consistency so that all
226    * three are of the same type.
227    */
228   virtual void SetParametricSpline(vtkParametricSpline*);
229   vtkGetObjectMacro(ParametricSpline,vtkParametricSpline);
230   //@}
231 
232   //@{
233   /**
234    * Set/Get the position of the spline handles. Call GetNumberOfHandles
235    * to determine the valid range of handle indices.
236    */
237   void SetHandlePosition(int handle, double x, double y, double z);
238   void SetHandlePosition(int handle, double xyz[3]);
239   void GetHandlePosition(int handle, double xyz[3]);
240   double* GetHandlePosition(int handle) VTK_SIZEHINT(3);
241   //@}
242 
243   //@{
244   /**
245    * Control whether the spline is open or closed. A closed spline forms
246    * a continuous loop: the first and last points are the same, and
247    * derivatives are continuous.  A minimum of 3 handles are required to
248    * form a closed loop.  This method enforces consistency with
249    * user supplied subclasses of vtkSpline.
250    */
251   void SetClosed(vtkTypeBool closed);
252   vtkGetMacro(Closed,vtkTypeBool);
253   vtkBooleanMacro(Closed,vtkTypeBool);
254   //@}
255 
256   /**
257    * Convenience method to determine whether the spline is
258    * closed in a geometric sense.  The widget may be set "closed" but still
259    * be geometrically open (e.g., a straight line).
260    */
261   int IsClosed();
262 
263   /**
264    * Get the approximate vs. the true arc length of the spline. Calculated as
265    * the summed lengths of the individual straight line segments. Use
266    * SetResolution to control the accuracy.
267    */
268   double GetSummedLength();
269 
270   /**
271    * Convenience method to allocate and set the handles from a vtkPoints
272    * instance.  If the first and last points are the same, the spline sets
273    * Closed to the on state and disregards the last point, otherwise Closed
274    * remains unchanged.
275    */
276   void InitializeHandles(vtkPoints* points);
277 
278   //@{
279   /**
280    * Turn on / off event processing for this widget. If off, the widget will
281    * not respond to user interaction
282    */
283   vtkSetClampMacro(ProcessEvents, vtkTypeBool, 0, 1);
284   vtkGetMacro(ProcessEvents, vtkTypeBool);
285   vtkBooleanMacro( ProcessEvents, vtkTypeBool );
286   //@}
287 
288 protected:
289   vtkSplineWidget();
290   ~vtkSplineWidget() override;
291 
292   // Manage the state of the widget
293   int State;
294   enum WidgetState
295   {
296     Start=0,
297     Moving,
298     Scaling,
299     Spinning,
300     Inserting,
301     Erasing,
302     Outside
303   };
304 
305   //handles the events
306   static void ProcessEventsHandler(vtkObject* object,
307                                    unsigned long event,
308                                    void* clientdata,
309                                    void* calldata);
310 
311   // ProcessEventsHandler() dispatches to these methods.
312   void OnLeftButtonDown();
313   void OnLeftButtonUp();
314   void OnMiddleButtonDown();
315   void OnMiddleButtonUp();
316   void OnRightButtonDown();
317   void OnRightButtonUp();
318   void OnMouseMove();
319 
320   // Controlling vars
321   int   ProjectionNormal;
322   double ProjectionPosition;
323   vtkTypeBool   ProjectToPlane;
324   vtkPlaneSource* PlaneSource;
325 
326   // Projection capabilities
327   void ProjectPointsToPlane();
328   void ProjectPointsToOrthoPlane();
329   void ProjectPointsToObliquePlane();
330 
331   // The spline
332   vtkParametricSpline *ParametricSpline;
333   vtkParametricFunctionSource *ParametricFunctionSource;
334   int NumberOfHandles;
335   vtkTypeBool Closed;
336   void BuildRepresentation();
337 
338   // The line segments
339   vtkActor           *LineActor;
340   void HighlightLine(int highlight);
341   int Resolution;
342 
343   // Glyphs representing hot spots (e.g., handles)
344   vtkActor          **Handle;
345   vtkSphereSource   **HandleGeometry;
346   void Initialize();
347   int  HighlightHandle(vtkProp *prop); //returns handle index or -1 on fail
348   void SizeHandles() override;
349   void InsertHandleOnLine(double* pos);
350   void EraseHandle(const int&);
351 
352   // Do the picking
353   vtkCellPicker *HandlePicker;
354   vtkCellPicker *LinePicker;
355   vtkActor *CurrentHandle;
356   int CurrentHandleIndex;
357 
358   // Register internal Pickers within PickingManager
359   void RegisterPickers() override;
360 
361   // Methods to manipulate the spline.
362   void MovePoint(double *p1, double *p2);
363   void Scale(double *p1, double *p2, int X, int Y);
364   void Translate(double *p1, double *p2);
365   void Spin(double *p1, double *p2, double *vpn);
366 
367   // Transform the control points (used for spinning)
368   vtkTransform *Transform;
369 
370   // Properties used to control the appearance of selected objects and
371   // the manipulator in general.
372   vtkProperty *HandleProperty;
373   vtkProperty *SelectedHandleProperty;
374   vtkProperty *LineProperty;
375   vtkProperty *SelectedLineProperty;
376   void CreateDefaultProperties();
377 
378   // For efficient spinning
379   double Centroid[3];
380   void CalculateCentroid();
381   vtkTypeBool  ProcessEvents;
382 
383 private:
384   vtkSplineWidget(const vtkSplineWidget&) = delete;
385   void operator=(const vtkSplineWidget&) = delete;
386 };
387 
388 #endif
389