1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkImageTracerWidget.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   vtkImageTracerWidget
17  * @brief   3D widget for tracing on planar props.
18  *
19  * vtkImageTracerWidget is different from other widgets in three distinct ways:
20  * 1) any sub-class of vtkProp can be input rather than just vtkProp3D, so that
21  * vtkImageActor can be set as the prop and then traced over, 2) the widget fires
22  * pick events at the input prop to decide where to move its handles, 3) the
23  * widget has 2D glyphs for handles instead of 3D spheres as is done in other
24  * sub-classes of vtk3DWidget. This widget is primarily designed for manually
25  * tracing over image data.
26  * The button actions and key modifiers are as follows for controlling the
27  * widget:
28  * 1) left button click over the image, hold and drag draws a free hand line.
29  * 2) left button click and release erases the widget line,
30  * if it exists, and repositions the first handle.
31  * 3) middle button click starts a snap drawn line.  The line is terminated by
32  * clicking the middle button while depressing the ctrl key.
33  * 4) when tracing a continuous or snap drawn line, if the last cursor position
34  * is within a specified tolerance to the first handle, the widget line will form
35  * a closed loop.
36  * 5) right button clicking and holding on any handle that is part of a snap
37  * drawn line allows handle dragging: existing line segments are updated
38  * accordingly.  If the path is open and AutoClose is set to On, the path can
39  * be closed by repositioning the first and last points over one another.
40  * 6) ctrl key + right button down on any handle will erase it: existing
41  * snap drawn line segments are updated accordingly.  If the line was formed by
42  * continuous tracing, the line is deleted leaving one handle.
43  * 7) shift key + right button down on any snap drawn line segment will insert
44  * a handle at the cursor position.  The line segment is split accordingly.
45  *
46  * @warning
47  * the input vtkDataSet should be vtkImageData.
48  *
49  * @sa
50  * vtk3DWidget vtkBoxWidget vtkLineWidget vtkPointWidget vtkSphereWidget
51  * vtkImagePlaneWidget vtkImplicitPlaneWidget vtkPlaneWidget
52  */
53 
54 #ifndef vtkImageTracerWidget_h
55 #define vtkImageTracerWidget_h
56 
57 #include "vtk3DWidget.h"
58 #include "vtkInteractionWidgetsModule.h" // For export macro
59 
60 class vtkAbstractPropPicker;
61 class vtkActor;
62 class vtkCellArray;
63 class vtkCellPicker;
64 class vtkFloatArray;
65 class vtkGlyphSource2D;
66 class vtkPoints;
67 class vtkPolyData;
68 class vtkProp;
69 class vtkProperty;
70 class vtkPropPicker;
71 class vtkTransform;
72 class vtkTransformPolyDataFilter;
73 
74 #define VTK_ITW_PROJECTION_YZ 0
75 #define VTK_ITW_PROJECTION_XZ 1
76 #define VTK_ITW_PROJECTION_XY 2
77 #define VTK_ITW_SNAP_CELLS 0
78 #define VTK_ITW_SNAP_POINTS 1
79 
80 class VTKINTERACTIONWIDGETS_EXPORT vtkImageTracerWidget : public vtk3DWidget
81 {
82 public:
83   /**
84    * Instantiate the object.
85    */
86   static vtkImageTracerWidget* New();
87 
88   vtkTypeMacro(vtkImageTracerWidget, vtk3DWidget);
89   void PrintSelf(ostream& os, vtkIndent indent) override;
90 
91   ///@{
92   /**
93    * Methods that satisfy the superclass' API.
94    */
95   void SetEnabled(int) override;
96   void PlaceWidget(double bounds[6]) override;
PlaceWidget()97   void PlaceWidget() override { this->Superclass::PlaceWidget(); }
PlaceWidget(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax)98   void PlaceWidget(
99     double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) override
100   {
101     this->Superclass::PlaceWidget(xmin, xmax, ymin, ymax, zmin, zmax);
102   }
103   ///@}
104 
105   ///@{
106   /**
107    * Set/Get the handle properties (the 2D glyphs are the handles). The
108    * properties of the handles when selected and normal can be manipulated.
109    */
110   virtual void SetHandleProperty(vtkProperty*);
111   vtkGetObjectMacro(HandleProperty, vtkProperty);
112   virtual void SetSelectedHandleProperty(vtkProperty*);
113   vtkGetObjectMacro(SelectedHandleProperty, vtkProperty);
114   ///@}
115 
116   ///@{
117   /**
118    * Set/Get the line properties. The properties of the line when selected
119    * and unselected can be manipulated.
120    */
121   virtual void SetLineProperty(vtkProperty*);
122   vtkGetObjectMacro(LineProperty, vtkProperty);
123   virtual void SetSelectedLineProperty(vtkProperty*);
124   vtkGetObjectMacro(SelectedLineProperty, vtkProperty);
125   ///@}
126 
127   /**
128    * Set the prop, usually a vtkImageActor, to trace over.
129    */
130   void SetViewProp(vtkProp* prop);
131 
132   ///@{
133   /**
134    * Force handles to be on a specific ortho plane. Default is Off.
135    */
136   vtkSetMacro(ProjectToPlane, vtkTypeBool);
137   vtkGetMacro(ProjectToPlane, vtkTypeBool);
138   vtkBooleanMacro(ProjectToPlane, vtkTypeBool);
139   ///@}
140 
141   ///@{
142   /**
143    * Set the projection normal.  The normal in SetProjectionNormal is 0,1,2
144    * for YZ,XZ,XY planes respectively.  Since the handles are 2D glyphs, it is
145    * necessary to specify a plane on which to generate them, even though
146    * ProjectToPlane may be turned off.
147    */
148   vtkSetClampMacro(ProjectionNormal, int, VTK_ITW_PROJECTION_YZ, VTK_ITW_PROJECTION_XY);
149   vtkGetMacro(ProjectionNormal, int);
SetProjectionNormalToXAxes()150   void SetProjectionNormalToXAxes() { this->SetProjectionNormal(0); }
SetProjectionNormalToYAxes()151   void SetProjectionNormalToYAxes() { this->SetProjectionNormal(1); }
SetProjectionNormalToZAxes()152   void SetProjectionNormalToZAxes() { this->SetProjectionNormal(2); }
153   ///@}
154 
155   ///@{
156   /**
157    * Set the position of the widgets' handles in terms of a plane's position.
158    * e.g., if ProjectionNormal is 0, all of the x-coordinate values of the
159    * handles are set to ProjectionPosition.  No attempt is made to ensure that
160    * the position is within the bounds of either the underlying image data or
161    * the prop on which tracing is performed.
162    */
163   void SetProjectionPosition(double position);
164   vtkGetMacro(ProjectionPosition, double);
165   ///@}
166 
167   ///@{
168   /**
169    * Force snapping to image data while tracing. Default is Off.
170    */
171   void SetSnapToImage(vtkTypeBool snap);
172   vtkGetMacro(SnapToImage, vtkTypeBool);
173   vtkBooleanMacro(SnapToImage, vtkTypeBool);
174   ///@}
175 
176   ///@{
177   /**
178    * In concert with a CaptureRadius value, automatically
179    * form a closed path by connecting first to last path points.
180    * Default is Off.
181    */
182   vtkSetMacro(AutoClose, vtkTypeBool);
183   vtkGetMacro(AutoClose, vtkTypeBool);
184   vtkBooleanMacro(AutoClose, vtkTypeBool);
185   ///@}
186 
187   ///@{
188   /**
189    * Set/Get the capture radius for automatic path closing.  For image
190    * data, capture radius should be half the distance between voxel/pixel
191    * centers.
192    * Default is 1.0
193    */
194   vtkSetMacro(CaptureRadius, double);
195   vtkGetMacro(CaptureRadius, double);
196   ///@}
197 
198   /**
199    * Grab the points and lines that define the traced path. These point values
200    * are guaranteed to be up-to-date when either the InteractionEvent or
201    * EndInteraction events are invoked. The user provides the vtkPolyData and
202    * the points and cells representing the line are added to it.
203    */
204   void GetPath(vtkPolyData* pd);
205 
206   /**
207    * Get the handles' geometric representation via vtkGlyphSource2D.
208    */
GetGlyphSource()209   vtkGlyphSource2D* GetGlyphSource() { return this->HandleGenerator; }
210 
211   ///@{
212   /**
213    * Set/Get the type of snapping to image data: center of a pixel/voxel or
214    * nearest point defining a pixel/voxel.
215    */
216   vtkSetClampMacro(ImageSnapType, int, VTK_ITW_SNAP_CELLS, VTK_ITW_SNAP_POINTS);
217   vtkGetMacro(ImageSnapType, int);
218   ///@}
219 
220   ///@{
221   /**
222    * Set/Get the handle position in terms of a zero-based array of handles.
223    */
224   void SetHandlePosition(int handle, double xyz[3]);
225   void SetHandlePosition(int handle, double x, double y, double z);
226   void GetHandlePosition(int handle, double xyz[3]);
227   double* GetHandlePosition(int handle) VTK_SIZEHINT(3);
228   ///@}
229 
230   ///@{
231   /**
232    * Get the number of handles.
233    */
234   vtkGetMacro(NumberOfHandles, int);
235   ///@}
236 
237   ///@{
238   /**
239    * Enable/disable mouse interaction when the widget is visible.
240    */
241   void SetInteraction(vtkTypeBool interact);
242   vtkGetMacro(Interaction, vtkTypeBool);
243   vtkBooleanMacro(Interaction, vtkTypeBool);
244   ///@}
245 
246   /**
247    * Initialize the widget with a set of points and generate
248    * lines between them.  If AutoClose is on it will handle the
249    * case wherein the first and last points are congruent.
250    */
251   void InitializeHandles(vtkPoints*);
252 
253   /**
254    * Is the path closed or open?
255    */
256   int IsClosed();
257 
258   ///@{
259   /**
260    * Enable/Disable mouse button events
261    */
262   vtkSetMacro(HandleLeftMouseButton, vtkTypeBool);
263   vtkGetMacro(HandleLeftMouseButton, vtkTypeBool);
264   vtkBooleanMacro(HandleLeftMouseButton, vtkTypeBool);
265   vtkSetMacro(HandleMiddleMouseButton, vtkTypeBool);
266   vtkGetMacro(HandleMiddleMouseButton, vtkTypeBool);
267   vtkBooleanMacro(HandleMiddleMouseButton, vtkTypeBool);
268   vtkSetMacro(HandleRightMouseButton, vtkTypeBool);
269   vtkGetMacro(HandleRightMouseButton, vtkTypeBool);
270   vtkBooleanMacro(HandleRightMouseButton, vtkTypeBool);
271   ///@}
272 
273 protected:
274   vtkImageTracerWidget();
275   ~vtkImageTracerWidget() override;
276 
277   // Manage the state of the widget
278   int State;
279   enum WidgetState
280   {
281     Start = 0,
282     Tracing,
283     Snapping,
284     Erasing,
285     Inserting,
286     Moving,
287     Translating,
288     Outside
289   };
290 
291   // handles the events
292   static void ProcessEvents(
293     vtkObject* object, unsigned long event, void* clientdata, void* calldata);
294 
295   // ProcessEvents() dispatches to these methods.
296   void OnLeftButtonDown();
297   void OnLeftButtonUp();
298   void OnMiddleButtonDown();
299   void OnMiddleButtonUp();
300   void OnRightButtonDown();
301   void OnRightButtonUp();
302   void OnMouseMove();
303 
304   void AddObservers();
305 
306   // Controlling ivars
307   vtkTypeBool Interaction;
308   int ProjectionNormal;
309   double ProjectionPosition;
310   vtkTypeBool ProjectToPlane;
311   int ImageSnapType;
312   vtkTypeBool SnapToImage;
313   double CaptureRadius; // tolerance for auto path close
314   vtkTypeBool AutoClose;
315   int IsSnapping;
316   int LastX;
317   int LastY;
318 
319   void Trace(int, int);
320   void Snap(double*);
321   void MovePoint(const double*, const double*);
322   void Translate(const double*, const double*);
323   void ClosePath();
324 
325   // 2D glyphs representing hot spots (e.g., handles)
326   vtkActor** Handle;
327   vtkPolyData** HandleGeometry;
328   vtkGlyphSource2D* HandleGenerator;
329 
330   // Transforms required as 2D glyphs are generated in the x-y plane
331   vtkTransformPolyDataFilter* TransformFilter;
332   vtkTransform* Transform;
333   vtkFloatArray* TemporaryHandlePoints;
334 
335   void AppendHandles(double*);
336   void ResetHandles();
337   void AllocateHandles(const int&);
338   void AdjustHandlePosition(const int&, double*);
339   int HighlightHandle(vtkProp*); // returns handle index or -1 on fail
340   void EraseHandle(const int&);
341   void SizeHandles() override;
342   void InsertHandleOnLine(double*);
343 
344   int NumberOfHandles;
345   vtkActor* CurrentHandle;
346   int CurrentHandleIndex;
347 
348   vtkProp* ViewProp;         // the prop we want to pick on
349   vtkPropPicker* PropPicker; // the prop's picker
350 
351   // Representation of the line
352   vtkPoints* LinePoints;
353   vtkCellArray* LineCells;
354   vtkActor* LineActor;
355   vtkPolyData* LineData;
356   vtkIdType CurrentPoints[2];
357 
358   void HighlightLine(const int&);
359   void BuildLinesFromHandles();
360   void ResetLine(double*);
361   void AppendLine(double*);
362   int PickCount;
363 
364   // Do the picking of the handles and the lines
365   vtkCellPicker* HandlePicker;
366   vtkCellPicker* LinePicker;
367   vtkAbstractPropPicker* CurrentPicker;
368 
369   // Register internal Pickers within PickingManager
370   void RegisterPickers() override;
371 
372   // Properties used to control the appearance of selected objects and
373   // the manipulator in general.
374   vtkProperty* HandleProperty;
375   vtkProperty* SelectedHandleProperty;
376   vtkProperty* LineProperty;
377   vtkProperty* SelectedLineProperty;
378   void CreateDefaultProperties();
379 
380   // Enable/Disable mouse button events
381   vtkTypeBool HandleLeftMouseButton;
382   vtkTypeBool HandleMiddleMouseButton;
383   vtkTypeBool HandleRightMouseButton;
384 
385 private:
386   vtkImageTracerWidget(const vtkImageTracerWidget&) = delete;
387   void operator=(const vtkImageTracerWidget&) = delete;
388 };
389 
390 #endif
391