1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Point Cloud Library (PCL) - www.pointclouds.org
5  *  Copyright (c) 2009-2012, Willow Garage, Inc.
6  *  Copyright (c) 2012-, Open Perception, Inc.
7  *
8  *  All rights reserved.
9  *
10  *  Redistribution and use in source and binary forms, with or without
11  *  modification, are permitted provided that the following conditions
12  *  are met:
13  *
14  *   * Redistributions of source code must retain the above copyright
15  *     notice, this list of conditions and the following disclaimer.
16  *   * Redistributions in binary form must reproduce the above
17  *     copyright notice, this list of conditions and the following
18  *     disclaimer in the documentation and/or other materials provided
19  *     with the distribution.
20  *   * Neither the name of the copyright holder(s) nor the names of its
21  *     contributors may be used to endorse or promote products derived
22  *     from this software without specific prior written permission.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  *  POSSIBILITY OF SUCH DAMAGE.
36  *
37  */
38 
39 #include <vtkCallbackCommand.h>
40 #include <vtkCamera.h>
41 #include <vtkImageSlice.h>
42 #include <vtkImageSliceMapper.h>
43 #include <vtkImageViewer.h>
44 #include <vtkObjectFactory.h>
45 #include <vtkRenderer.h>
46 #include <vtkVersion.h>
47 
48 #include <pcl/visualization/image_viewer.h>
49 #include <pcl/visualization/common/float_image_utils.h>
50 #include <pcl/visualization/keyboard_event.h>
51 #include <pcl/visualization/mouse_event.h>
52 #include <pcl/common/time.h>
53 #include <pcl/visualization/vtk/vtkRenderWindowInteractorFix.h>
54 
55 //////////////////////////////////////////////////////////////////////////////////////////
ImageViewer(const std::string & window_title)56 pcl::visualization::ImageViewer::ImageViewer (const std::string& window_title)
57   : mouse_command_ (vtkSmartPointer<vtkCallbackCommand>::New ())
58   , keyboard_command_ (vtkSmartPointer<vtkCallbackCommand>::New ())
59   , win_ (vtkSmartPointer<vtkRenderWindow>::New ())
60   , ren_ (vtkSmartPointer<vtkRenderer>::New ())
61   , slice_ (vtkSmartPointer<vtkImageSlice>::New ())
62   , interactor_style_ (vtkSmartPointer<ImageViewerInteractorStyle>::New ())
63   , data_size_ (0)
64   , stopped_ ()
65   , timer_id_ ()
66   , algo_ (vtkSmartPointer<vtkImageFlip>::New ())
67 {
68   interactor_ = vtkSmartPointer <vtkRenderWindowInteractor>::Take (vtkRenderWindowInteractorFixNew ());
69 
70   // Prepare for image flip
71   algo_->SetInterpolationModeToCubic ();
72   algo_->PreserveImageExtentOn ();
73   algo_->FlipAboutOriginOn ();
74   algo_->SetFilteredAxis (1);
75 
76   // blend_->SetBlendModeToNormal ();
77   // blend_->SetNumberOfThreads (1);
78 
79   // Set the mouse/keyboard callbacks
80   mouse_command_->SetClientData (this);
81   mouse_command_->SetCallback (ImageViewer::MouseCallback);
82 
83   keyboard_command_->SetClientData (this);
84   keyboard_command_->SetCallback (ImageViewer::KeyboardCallback);
85 
86   // Create our own  interactor and set the window title
87   win_->SetSize (640, 480);
88   win_->AddRenderer (ren_);
89   win_->SetWindowName (window_title.c_str ());
90   interactor_->SetRenderWindow (win_);
91 
92   vtkSmartPointer<vtkImageData> empty_image = vtkSmartPointer<vtkImageData>::New ();
93   vtkSmartPointer<vtkImageSliceMapper> map = vtkSmartPointer<vtkImageSliceMapper>::New ();
94   map->SetInputData (empty_image);
95   slice_->SetMapper (map);
96   ren_->AddViewProp (slice_);
97   ren_->GetActiveCamera ()->ParallelProjectionOn ();
98   interactor_->SetInteractorStyle (interactor_style_);
99 
100   // Initialize and create timer
101   interactor_->Initialize ();
102   timer_id_ = interactor_->CreateRepeatingTimer (0);
103 
104   // Set the exit callbacks
105   exit_main_loop_timer_callback_ = vtkSmartPointer<ExitMainLoopTimerCallback>::New ();
106   exit_main_loop_timer_callback_->window = this;
107   exit_main_loop_timer_callback_->right_timer_id = -1;
108   interactor_->AddObserver (vtkCommand::TimerEvent, exit_main_loop_timer_callback_);
109 
110   exit_callback_ = vtkSmartPointer<ExitCallback>::New ();
111   exit_callback_->window = this;
112   interactor_->AddObserver (vtkCommand::ExitEvent, exit_callback_);
113 
114   // Reset camera (flip it vertically)
115   resetStoppedFlag ();
116 
117   PCL_DEBUG ("[pcl::visualization::ImageViewer] VTK version found: %d.%d\n", VTK_MAJOR_VERSION, VTK_MINOR_VERSION);
118 }
119 
120 //////////////////////////////////////////////////////////////////////////////////////////
~ImageViewer()121 pcl::visualization::ImageViewer::~ImageViewer ()
122 {
123    interactor_->DestroyTimer (timer_id_);
124 }
125 
126 //////////////////////////////////////////////////////////////////////////////////////////
127 void
addRGBImage(const unsigned char * rgb_data,unsigned width,unsigned height,const std::string & layer_id,double opacity,bool autoresize)128 pcl::visualization::ImageViewer::addRGBImage (
129     const unsigned char* rgb_data, unsigned width, unsigned height,
130     const std::string &layer_id, double opacity, bool autoresize)
131 {
132   if (autoresize &&
133       (unsigned (getSize ()[0]) != width ||
134       unsigned (getSize ()[1]) != height))
135     setSize (width, height);
136 
137   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
138   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
139   if (am_it == layer_map_.end ())
140   {
141     PCL_DEBUG ("[pcl::visualization::ImageViewer::addRGBImage] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
142     am_it = createLayer (layer_id, width, height, opacity, false);
143   }
144 
145   void* data = const_cast<void*> (reinterpret_cast<const void*> (rgb_data));
146 
147   vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New ();
148   image->SetExtent (0, width - 1, 0, height - 1, 0, 0);
149   image->AllocateScalars (VTK_UNSIGNED_CHAR, 3);
150   image->GetPointData ()->GetScalars ()->SetVoidArray (data, 3 * width * height, 1);
151   algo_->SetInputData (image);
152   algo_->Update ();
153   slice_->GetMapper ()->SetInputConnection (algo_->GetOutputPort ());
154   ren_->ResetCamera ();
155   ren_->GetActiveCamera ()->SetParallelScale (0.5 * win_->GetSize ()[1]);
156 }
157 
158 //////////////////////////////////////////////////////////////////////////////////////////
159 void
showRGBImage(const unsigned char * rgb_data,unsigned width,unsigned height,const std::string & layer_id,double opacity)160 pcl::visualization::ImageViewer::showRGBImage (
161     const unsigned char* rgb_data, unsigned width, unsigned height,
162     const std::string &layer_id, double opacity)
163 {
164   addRGBImage (rgb_data, width, height, layer_id, opacity);
165   render ();
166 }
167 
168 //////////////////////////////////////////////////////////////////////////////////////////
169 void
addMonoImage(const unsigned char * rgb_data,unsigned width,unsigned height,const std::string & layer_id,double opacity)170 pcl::visualization::ImageViewer::addMonoImage (
171     const unsigned char* rgb_data, unsigned width, unsigned height,
172     const std::string &layer_id, double opacity)
173 {
174   if (unsigned (getSize ()[0]) != width ||
175       unsigned (getSize ()[1]) != height)
176     setSize (width, height);
177 
178   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
179   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
180   if (am_it == layer_map_.end ())
181   {
182     PCL_DEBUG ("[pcl::visualization::ImageViewer::showMonoImage] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
183     am_it = createLayer (layer_id, width, height, opacity, false);
184   }
185 
186   void* data = const_cast<void*> (reinterpret_cast<const void*> (rgb_data));
187 
188   vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New ();
189   image->SetExtent (0, width - 1, 0, height - 1, 0, 0);
190   image->AllocateScalars (VTK_UNSIGNED_CHAR, 1);
191   image->GetPointData ()->GetScalars ()->SetVoidArray (data, width * height, 1);
192 
193   algo_->SetInputData (image);
194   algo_->Update ();
195   slice_->GetMapper ()->SetInputConnection (algo_->GetOutputPort ());
196   ren_->ResetCamera ();
197   ren_->GetActiveCamera ()->SetParallelScale (0.5 * win_->GetSize ()[1]);
198 }
199 
200 
201 //////////////////////////////////////////////////////////////////////////////////////////
202 void
showMonoImage(const unsigned char * rgb_data,unsigned width,unsigned height,const std::string & layer_id,double opacity)203 pcl::visualization::ImageViewer::showMonoImage (
204     const unsigned char* rgb_data, unsigned width, unsigned height,
205     const std::string &layer_id, double opacity)
206 {
207   addMonoImage (rgb_data, width, height, layer_id, opacity);
208   render ();
209 }
210 
211 //////////////////////////////////////////////////////////////////////////////////////////
212 void
addMonoImage(const pcl::PointCloud<pcl::Intensity> & cloud,const std::string & layer_id,double opacity)213 pcl::visualization::ImageViewer::addMonoImage (
214     const pcl::PointCloud<pcl::Intensity> &cloud,
215     const std::string &layer_id, double opacity)
216 {
217   if (data_size_ < cloud.width * cloud.height)
218   {
219     data_size_ = cloud.width * cloud.height * 3;
220     data_.reset (new unsigned char[data_size_]);
221   }
222 
223   convertIntensityCloudToUChar (cloud, data_);
224 
225   return (addMonoImage (data_.get (), cloud.width, cloud.height, layer_id, opacity));
226 }
227 
228 //////////////////////////////////////////////////////////////////////////////////////////
229 void
showMonoImage(const pcl::PointCloud<pcl::Intensity> & cloud,const std::string & layer_id,double opacity)230 pcl::visualization::ImageViewer::showMonoImage (
231     const pcl::PointCloud<pcl::Intensity> &cloud,
232     const std::string &layer_id, double opacity)
233 {
234   addMonoImage (cloud, layer_id, opacity);
235   render ();
236 }
237 
238 //////////////////////////////////////////////////////////////////////////////////////////
239 void
addMonoImage(const pcl::PointCloud<pcl::Intensity8u> & cloud,const std::string & layer_id,double opacity)240 pcl::visualization::ImageViewer::addMonoImage (
241     const pcl::PointCloud<pcl::Intensity8u> &cloud,
242     const std::string &layer_id, double opacity)
243 {
244   if (data_size_ < cloud.width * cloud.height)
245   {
246     data_size_ = cloud.width * cloud.height * 3;
247     data_.reset (new unsigned char[data_size_]);
248   }
249 
250   convertIntensityCloud8uToUChar (cloud, data_);
251 
252   return (addMonoImage (data_.get (), cloud.width, cloud.height, layer_id, opacity));
253 }
254 
255 //////////////////////////////////////////////////////////////////////////////////////////
256 void
showMonoImage(const pcl::PointCloud<pcl::Intensity8u> & cloud,const std::string & layer_id,double opacity)257 pcl::visualization::ImageViewer::showMonoImage (
258     const pcl::PointCloud<pcl::Intensity8u> &cloud,
259     const std::string &layer_id, double opacity)
260 {
261   addMonoImage (cloud, layer_id, opacity);
262   render ();
263 }
264 
265 //////////////////////////////////////////////////////////////////////////////////////////
266 void
addFloatImage(const float * float_image,unsigned int width,unsigned int height,float min_value,float max_value,bool grayscale,const std::string & layer_id,double opacity)267 pcl::visualization::ImageViewer::addFloatImage (
268     const float* float_image, unsigned int width, unsigned int height,
269     float min_value, float max_value, bool grayscale,
270     const std::string &layer_id, double opacity)
271 {
272   unsigned char* rgb_image = FloatImageUtils::getVisualImage (float_image, width, height,
273                                                               min_value, max_value, grayscale);
274   addRGBImage (rgb_image, width, height, layer_id, opacity);
275   image_data_.push_back (rgb_image);
276 }
277 
278 //////////////////////////////////////////////////////////////////////////////////////////
279 void
showFloatImage(const float * float_image,unsigned int width,unsigned int height,float min_value,float max_value,bool grayscale,const std::string & layer_id,double opacity)280 pcl::visualization::ImageViewer::showFloatImage (
281     const float* float_image, unsigned int width, unsigned int height,
282     float min_value, float max_value, bool grayscale,
283     const std::string &layer_id, double opacity)
284 {
285   addFloatImage (float_image, width, height, min_value, max_value, grayscale, layer_id, opacity);
286   render ();
287  }
288 
289 //////////////////////////////////////////////////////////////////////////////////////////
290 void
addAngleImage(const float * angle_image,unsigned int width,unsigned int height,const std::string & layer_id,double opacity)291 pcl::visualization::ImageViewer::addAngleImage (
292     const float* angle_image, unsigned int width, unsigned int height,
293     const std::string &layer_id, double opacity)
294 {
295   unsigned char* rgb_image = FloatImageUtils::getVisualAngleImage (angle_image, width, height);
296   addRGBImage (rgb_image, width, height, layer_id, opacity);
297   image_data_.push_back (rgb_image);
298 }
299 
300 //////////////////////////////////////////////////////////////////////////////////////////
301 void
showAngleImage(const float * angle_image,unsigned int width,unsigned int height,const std::string & layer_id,double opacity)302 pcl::visualization::ImageViewer::showAngleImage (
303     const float* angle_image, unsigned int width, unsigned int height,
304     const std::string &layer_id, double opacity)
305 {
306   addAngleImage (angle_image, width, height, layer_id, opacity);
307   render ();
308 }
309 
310 //////////////////////////////////////////////////////////////////////////////////////////
311 void
addHalfAngleImage(const float * angle_image,unsigned int width,unsigned int height,const std::string & layer_id,double opacity)312 pcl::visualization::ImageViewer::addHalfAngleImage (
313     const float* angle_image, unsigned int width, unsigned int height,
314     const std::string &layer_id, double opacity)
315 {
316   unsigned char* rgb_image = FloatImageUtils::getVisualHalfAngleImage (angle_image, width, height);
317   addRGBImage (rgb_image, width, height, layer_id, opacity);
318   image_data_.push_back (rgb_image);
319 }
320 
321 //////////////////////////////////////////////////////////////////////////////////////////
322 void
showHalfAngleImage(const float * angle_image,unsigned int width,unsigned int height,const std::string & layer_id,double opacity)323 pcl::visualization::ImageViewer::showHalfAngleImage (
324     const float* angle_image, unsigned int width, unsigned int height,
325     const std::string &layer_id, double opacity)
326 {
327   addHalfAngleImage (angle_image, width, height, layer_id, opacity);
328   render ();
329 }
330 
331 //////////////////////////////////////////////////////////////////////////////////////////
332 void
addShortImage(const unsigned short * short_image,unsigned int width,unsigned int height,unsigned short min_value,unsigned short max_value,bool grayscale,const std::string & layer_id,double opacity)333 pcl::visualization::ImageViewer::addShortImage (
334     const unsigned short* short_image, unsigned int width, unsigned int height,
335     unsigned short min_value, unsigned short max_value, bool grayscale,
336     const std::string &layer_id, double opacity)
337 {
338   unsigned char* rgb_image = FloatImageUtils::getVisualImage (short_image, width, height,
339                                                               min_value, max_value, grayscale);
340   addRGBImage (rgb_image, width, height, layer_id, opacity);
341   image_data_.push_back (rgb_image);
342 }
343 
344 //////////////////////////////////////////////////////////////////////////////////////////
345 void
showShortImage(const unsigned short * short_image,unsigned int width,unsigned int height,unsigned short min_value,unsigned short max_value,bool grayscale,const std::string & layer_id,double opacity)346 pcl::visualization::ImageViewer::showShortImage (
347     const unsigned short* short_image, unsigned int width, unsigned int height,
348     unsigned short min_value, unsigned short max_value, bool grayscale,
349     const std::string &layer_id, double opacity)
350 {
351   addShortImage (short_image, width, height, min_value, max_value, grayscale, layer_id, opacity);
352   render ();
353 }
354 
355 //////////////////////////////////////////////////////////////////////////////////////////
356 void
spin()357 pcl::visualization::ImageViewer::spin ()
358 {
359   render ();
360   resetStoppedFlag ();
361   // Render the window before we start the interactor
362   //interactor_->Render ();
363   interactor_->Start ();
364 }
365 
366 //////////////////////////////////////////////////////////////////////////////////////////
367 void
spinOnce(int time,bool force_redraw)368 pcl::visualization::ImageViewer::spinOnce (int time, bool force_redraw)
369 {
370   if (force_redraw)
371   {
372     render ();
373     //interactor_->Render ();
374   }
375 
376   if (time <= 0)
377     time = 1;
378 
379   DO_EVERY (1.0 / interactor_->GetDesiredUpdateRate (),
380     exit_main_loop_timer_callback_->right_timer_id = interactor_->CreateRepeatingTimer (time);
381     interactor_->Start ();
382     interactor_->DestroyTimer (exit_main_loop_timer_callback_->right_timer_id);
383   );
384   for(auto &i : image_data_)
385     delete [] i;
386   image_data_.clear ();
387 }
388 
389 //////////////////////////////////////////////////////////////////////////////////////////
390 boost::signals2::connection
registerMouseCallback(std::function<void (const pcl::visualization::MouseEvent &)> callback)391 pcl::visualization::ImageViewer::registerMouseCallback (
392     std::function<void (const pcl::visualization::MouseEvent&)> callback)
393 {
394   // just add observer at first time when a callback is registered
395   if (mouse_signal_.empty ())
396   {
397     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::MouseMoveEvent, mouse_command_);
398     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::MiddleButtonPressEvent, mouse_command_);
399     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::MiddleButtonReleaseEvent, mouse_command_);
400     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::MouseWheelBackwardEvent, mouse_command_);
401     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::MouseWheelForwardEvent, mouse_command_);
402     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::LeftButtonPressEvent, mouse_command_);
403     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::LeftButtonReleaseEvent, mouse_command_);
404     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::RightButtonPressEvent, mouse_command_);
405     interactor_->GetInteractorStyle ()->AddObserver (vtkCommand::RightButtonReleaseEvent, mouse_command_);
406   }
407   return (mouse_signal_.connect (callback));
408 }
409 
410 //////////////////////////////////////////////////////////////////////////////////////////
411 boost::signals2::connection
registerKeyboardCallback(std::function<void (const pcl::visualization::KeyboardEvent &)> callback)412 pcl::visualization::ImageViewer::registerKeyboardCallback (
413     std::function<void (const pcl::visualization::KeyboardEvent&)> callback)
414 {
415   // just add observer at first time when a callback is registered
416   if (keyboard_signal_.empty ())
417   {
418     interactor_->AddObserver (vtkCommand::KeyPressEvent, keyboard_command_);
419     interactor_->AddObserver (vtkCommand::KeyReleaseEvent, keyboard_command_);
420   }
421 
422   return (keyboard_signal_.connect (callback));
423 }
424 
425 //////////////////////////////////////////////////////////////////////////////////////////
426 void
emitMouseEvent(unsigned long event_id)427 pcl::visualization::ImageViewer::emitMouseEvent (unsigned long event_id)
428 {
429   //interactor_->GetMousePosition (&x, &y);
430   int x = this->interactor_->GetEventPosition()[0];
431   int y = this->interactor_->GetEventPosition()[1];
432   MouseEvent event (MouseEvent::MouseMove, MouseEvent::NoButton, x, y,
433                     interactor_->GetAltKey (),
434                     interactor_->GetControlKey (),
435                     interactor_->GetShiftKey ());
436   bool repeat = false;
437   switch (event_id)
438   {
439     case vtkCommand::MouseMoveEvent :
440       event.setType (MouseEvent::MouseMove);
441       break;
442 
443     case vtkCommand::LeftButtonPressEvent :
444       event.setButton (MouseEvent::LeftButton);
445       if (interactor_->GetRepeatCount () == 0)
446         event.setType (MouseEvent::MouseButtonPress);
447       else
448         event.setType (MouseEvent::MouseDblClick);
449       break;
450 
451     case vtkCommand::LeftButtonReleaseEvent :
452       event.setButton (MouseEvent::LeftButton);
453       event.setType (MouseEvent::MouseButtonRelease);
454       break;
455 
456     case vtkCommand::RightButtonPressEvent :
457       event.setButton (MouseEvent::RightButton);
458       if (interactor_->GetRepeatCount () == 0)
459         event.setType (MouseEvent::MouseButtonPress);
460       else
461         event.setType (MouseEvent::MouseDblClick);
462       break;
463 
464     case vtkCommand::RightButtonReleaseEvent :
465       event.setButton (MouseEvent::RightButton);
466       event.setType (MouseEvent::MouseButtonRelease);
467       break;
468 
469     case vtkCommand::MiddleButtonPressEvent :
470       event.setButton (MouseEvent::MiddleButton);
471       if (interactor_->GetRepeatCount () == 0)
472         event.setType (MouseEvent::MouseButtonPress);
473       else
474         event.setType (MouseEvent::MouseDblClick);
475       break;
476 
477     case vtkCommand::MiddleButtonReleaseEvent :
478       event.setButton (MouseEvent::MiddleButton);
479       event.setType (MouseEvent::MouseButtonRelease);
480       break;
481 
482     case vtkCommand::MouseWheelBackwardEvent :
483       event.setButton (MouseEvent::VScroll);
484       event.setType (MouseEvent::MouseScrollDown);
485       if (interactor_->GetRepeatCount () != 0)
486         repeat = true;
487       break;
488 
489     case vtkCommand::MouseWheelForwardEvent :
490       event.setButton (MouseEvent::VScroll);
491       event.setType (MouseEvent::MouseScrollUp);
492       if (interactor_->GetRepeatCount () != 0)
493         repeat = true;
494       break;
495     default:
496       return;
497   }
498 
499   mouse_signal_ (event);
500   if (repeat)
501     mouse_signal_ (event);
502 }
503 
504 //////////////////////////////////////////////////////////////////////////////////////////
505 void
emitKeyboardEvent(unsigned long event_id)506 pcl::visualization::ImageViewer::emitKeyboardEvent (unsigned long event_id)
507 {
508   KeyboardEvent event (bool(event_id == vtkCommand::KeyPressEvent), interactor_->GetKeySym (),  interactor_->GetKeyCode (), interactor_->GetAltKey (), interactor_->GetControlKey (), interactor_->GetShiftKey ());
509   keyboard_signal_ (event);
510 }
511 
512 //////////////////////////////////////////////////////////////////////////////////////////
513 void
MouseCallback(vtkObject *,unsigned long eid,void * clientdata,void *)514 pcl::visualization::ImageViewer::MouseCallback (vtkObject*, unsigned long eid, void* clientdata, void*)
515 {
516   ImageViewer* window = reinterpret_cast<ImageViewer*> (clientdata);
517   window->emitMouseEvent (eid);
518 }
519 
520 //////////////////////////////////////////////////////////////////////////////////////////
521 void
KeyboardCallback(vtkObject *,unsigned long eid,void * clientdata,void *)522 pcl::visualization::ImageViewer::KeyboardCallback (vtkObject*, unsigned long eid, void* clientdata, void*)
523 {
524   ImageViewer* window = reinterpret_cast<ImageViewer*> (clientdata);
525   window->emitKeyboardEvent (eid);
526 }
527 
528 //////////////////////////////////////////////////////////////////////////////////////////
529 pcl::visualization::ImageViewer::LayerMap::iterator
createLayer(const std::string & layer_id,int width,int height,double opacity,bool fill_box)530 pcl::visualization::ImageViewer::createLayer (
531     const std::string &layer_id, int width, int height, double opacity, bool fill_box)
532 {
533   Layer l;
534   l.layer_name = layer_id;
535   // Create a new layer
536   l.actor = vtkSmartPointer<vtkContextActor>::New ();
537   l.actor->PickableOff ();
538   l.actor->DragableOff ();
539   if (fill_box)
540   {
541     vtkSmartPointer<context_items::FilledRectangle> rect = vtkSmartPointer<context_items::FilledRectangle>::New ();
542     rect->setColors (0,0,0);
543     rect->setOpacity (opacity);
544     rect->set (0, 0, static_cast<float> (width), static_cast<float> (height));
545     l.actor->GetScene ()->AddItem (rect);
546   }
547   ren_->AddActor (l.actor);
548   // Add another element
549   layer_map_.push_back (l);
550 
551   return (layer_map_.end () - 1);
552 }
553 
554 //////////////////////////////////////////////////////////////////////////////////////////
555 bool
addLayer(const std::string & layer_id,int width,int height,double opacity)556 pcl::visualization::ImageViewer::addLayer (
557     const std::string &layer_id, int width, int height, double opacity)
558 {
559   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
560   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
561   if (am_it != layer_map_.end ())
562   {
563     PCL_DEBUG ("[pcl::visualization::ImageViewer::addLayer] Layer with ID='%s' already exists!\n", layer_id.c_str ());
564     return (false);
565   }
566 
567   createLayer (layer_id, width, height, opacity, false);
568 
569   return (true);
570 }
571 
572 ///////////////////////////////////////////////////////////////////////////////////////////
573 void
removeLayer(const std::string & layer_id)574 pcl::visualization::ImageViewer::removeLayer (const std::string &layer_id)
575 {
576   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
577   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
578   if (am_it == layer_map_.end ())
579   {
580     PCL_DEBUG ("[pcl::visualization::ImageViewer::removeLayer] No layer with ID='%s' found.\n", layer_id.c_str ());
581     return;
582   }
583   ren_->RemoveActor (am_it->actor);
584   layer_map_.erase (am_it);
585 }
586 
587 //////////////////////////////////////////////////////////////////////////////////////////
588 bool
addCircle(unsigned int x,unsigned int y,double radius,double r,double g,double b,const std::string & layer_id,double opacity)589 pcl::visualization::ImageViewer::addCircle (
590     unsigned int x, unsigned int y, double radius, double r, double g, double b,
591     const std::string &layer_id, double opacity)
592 {
593   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
594   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
595   if (am_it == layer_map_.end ())
596   {
597     PCL_DEBUG ("[pcl::visualization::ImageViewer::addCircle] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
598     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
599   }
600 
601   vtkSmartPointer<context_items::Circle> circle = vtkSmartPointer<context_items::Circle>::New ();
602   circle->setColors (static_cast<unsigned char> (255.0 * r),
603                      static_cast<unsigned char> (255.0 * g),
604                      static_cast<unsigned char> (255.0 * b));
605   circle->setOpacity (opacity);
606   circle->set (static_cast<float> (x), static_cast<float> (y), static_cast<float> (radius));
607   am_it->actor->GetScene ()->AddItem (circle);
608 
609   return (true);
610 }
611 
612 //////////////////////////////////////////////////////////////////////////////////////////
613 bool
addCircle(unsigned int x,unsigned int y,double radius,const std::string & layer_id,double opacity)614 pcl::visualization::ImageViewer::addCircle (unsigned int x, unsigned int y, double radius,
615                                             const std::string &layer_id, double opacity)
616 {
617   return (addCircle (x, y, radius, 0.0, 1.0, 0.0, layer_id, opacity));
618 }
619 
620 //////////////////////////////////////////////////////////////////////////////////////////
621 bool
addFilledRectangle(unsigned int x_min,unsigned int x_max,unsigned int y_min,unsigned int y_max,double r,double g,double b,const std::string & layer_id,double opacity)622 pcl::visualization::ImageViewer::addFilledRectangle (
623     unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
624     double r, double g, double b, const std::string &layer_id, double opacity)
625 {
626   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
627   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
628   if (am_it == layer_map_.end ())
629   {
630     PCL_DEBUG ("[pcl::visualization::ImageViewer::addFilledRectangle] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
631     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
632   }
633 
634   vtkSmartPointer<context_items::FilledRectangle> rect = vtkSmartPointer<context_items::FilledRectangle>::New ();
635   rect->setColors (static_cast<unsigned char> (255.0 * r),
636                    static_cast<unsigned char> (255.0 * g),
637                    static_cast<unsigned char> (255.0 * b));
638   rect->setOpacity (opacity);
639   rect->set (static_cast<float> (x_min), static_cast<float> (y_min),
640              static_cast<float> (x_max - x_min), static_cast<float> (y_max - y_min));
641   am_it->actor->GetScene ()->AddItem (rect);
642 
643   return (true);
644 }
645 
646 //////////////////////////////////////////////////////////////////////////////////////////
647 bool
addFilledRectangle(unsigned int x_min,unsigned int x_max,unsigned int y_min,unsigned int y_max,const std::string & layer_id,double opacity)648 pcl::visualization::ImageViewer::addFilledRectangle (
649     unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
650     const std::string &layer_id, double opacity)
651 {
652   return (addFilledRectangle (x_min, x_max, y_min, y_max, 0.0, 1.0, 0.0, layer_id, opacity));
653 }
654 
655 //////////////////////////////////////////////////////////////////////////////////////////
656 bool
addRectangle(unsigned int x_min,unsigned int x_max,unsigned int y_min,unsigned int y_max,double r,double g,double b,const std::string & layer_id,double opacity)657 pcl::visualization::ImageViewer::addRectangle (
658     unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
659     double r, double g, double b, const std::string &layer_id, double opacity)
660 {
661   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
662   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
663   if (am_it == layer_map_.end ())
664   {
665     PCL_DEBUG ("[pcl::visualization::ImageViewer::addRectangle] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
666     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
667   }
668 
669   vtkSmartPointer<context_items::Rectangle> rect = vtkSmartPointer<context_items::Rectangle>::New ();
670   rect->setColors (static_cast<unsigned char> (255.0 * r),
671                    static_cast<unsigned char> (255.0 * g),
672                    static_cast<unsigned char> (255.0 * b));
673   rect->setOpacity (opacity);
674   rect->set (static_cast<float> (x_min), static_cast<float> (y_min),
675              static_cast<float> (x_max), static_cast<float> (y_max));
676   am_it->actor->GetScene ()->AddItem (rect);
677 
678   return (true);
679 }
680 
681 //////////////////////////////////////////////////////////////////////////////////////////
682 bool
addRectangle(unsigned int x_min,unsigned int x_max,unsigned int y_min,unsigned int y_max,const std::string & layer_id,double opacity)683 pcl::visualization::ImageViewer::addRectangle (
684     unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
685     const std::string &layer_id, double opacity)
686 {
687   return (addRectangle (x_min, x_max, y_min, y_max, 0.0, 1.0, 0.0, layer_id, opacity));
688 }
689 
690 //////////////////////////////////////////////////////////////////////////////////////////
691 bool
addRectangle(const pcl::PointXY & min_pt,const pcl::PointXY & max_pt,double r,double g,double b,const std::string & layer_id,double opacity)692 pcl::visualization::ImageViewer::addRectangle (
693     const pcl::PointXY &min_pt, const pcl::PointXY &max_pt,
694     double r, double g, double b, const std::string &layer_id, double opacity)
695 {
696   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
697   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
698   if (am_it == layer_map_.end ())
699   {
700     PCL_DEBUG ("[pcl::visualization::ImageViewer::addRectangle] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
701     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
702   }
703 
704   vtkSmartPointer<context_items::Rectangle> rect = vtkSmartPointer<context_items::Rectangle>::New ();
705   rect->setColors (static_cast<unsigned char> (255.0 * r),
706                    static_cast<unsigned char> (255.0 * g),
707                    static_cast<unsigned char> (255.0 * b));
708   rect->setOpacity (opacity);
709   rect->set (min_pt.x, min_pt.y, max_pt.x, max_pt.y);
710   am_it->actor->GetScene ()->AddItem (rect);
711 
712   return (true);
713 }
714 
715 //////////////////////////////////////////////////////////////////////////////////////////
716 bool
addRectangle(const pcl::PointXY & min_pt,const pcl::PointXY & max_pt,const std::string & layer_id,double opacity)717 pcl::visualization::ImageViewer::addRectangle (
718     const pcl::PointXY &min_pt, const pcl::PointXY &max_pt,
719     const std::string &layer_id, double opacity)
720 {
721   return (addRectangle (min_pt, max_pt, 0.0, 1.0, 0.0, layer_id, opacity));
722 }
723 
724 //////////////////////////////////////////////////////////////////////////////////////////
725 bool
addLine(unsigned int x_min,unsigned int y_min,unsigned int x_max,unsigned int y_max,double r,double g,double b,const std::string & layer_id,double opacity)726 pcl::visualization::ImageViewer::addLine (unsigned int x_min, unsigned int y_min,
727                                           unsigned int x_max, unsigned int y_max,
728                                           double r, double g, double b,
729                                           const std::string &layer_id, double opacity)
730 {
731   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
732   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
733   if (am_it == layer_map_.end ())
734   {
735     PCL_DEBUG ("[pcl::visualization::ImageViewer::addLine] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
736     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
737   }
738 
739   vtkSmartPointer<context_items::Line> line = vtkSmartPointer<context_items::Line>::New ();
740   line->setColors (static_cast<unsigned char> (255.0 * r),
741                    static_cast<unsigned char> (255.0 * g),
742                    static_cast<unsigned char> (255.0 * b));
743   line->setOpacity (opacity);
744   line->set (static_cast<float> (x_min), static_cast<float> (y_min),
745              static_cast<float> (x_max), static_cast<float> (y_max));
746   am_it->actor->GetScene ()->AddItem (line);
747 
748   return (true);
749 }
750 
751 //////////////////////////////////////////////////////////////////////////////////////////
752 bool
addLine(unsigned int x_min,unsigned int y_min,unsigned int x_max,unsigned int y_max,const std::string & layer_id,double opacity)753 pcl::visualization::ImageViewer::addLine (unsigned int x_min, unsigned int y_min,
754                                           unsigned int x_max, unsigned int y_max,
755                                           const std::string &layer_id, double opacity)
756 {
757   return (addLine (x_min, y_min, x_max, y_max, 0.0, 1.0, 0.0, layer_id, opacity));
758 }
759 
760 //////////////////////////////////////////////////////////////////////////////////////////
761 bool
addText(unsigned int x,unsigned int y,const std::string & text_string,double r,double g,double b,const std::string & layer_id,double opacity)762 pcl::visualization::ImageViewer::addText (unsigned int x, unsigned int y,
763                                           const std::string& text_string,
764                                           double r, double g, double b,
765                                           const std::string &layer_id, double opacity)
766 {
767   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
768   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
769   if (am_it == layer_map_.end ())
770   {
771     PCL_DEBUG ("[pcl::visualization::ImageViewer::addText] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
772     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
773   }
774 
775   vtkSmartPointer<context_items::Text> text = vtkSmartPointer<context_items::Text>::New ();
776   text->setColors (static_cast<unsigned char> (255.0 * r),
777                    static_cast<unsigned char> (255.0 * g),
778                    static_cast<unsigned char> (255.0 * b));
779   text->setOpacity (opacity);
780   text->set (static_cast<float> (x), static_cast<float> (y), text_string);
781   am_it->actor->GetScene ()->AddItem (text);
782 
783   return (true);
784 }
785 
786 //////////////////////////////////////////////////////////////////////////////////////////
787 bool
addText(unsigned int x,unsigned int y,const std::string & text,const std::string & layer_id,double opacity)788 pcl::visualization::ImageViewer::addText (unsigned int x, unsigned int y, const std::string& text,
789                                           const std::string &layer_id, double opacity)
790 {
791   return (addText (x, y, text, 0.0, 1.0, 0.0, layer_id, opacity));
792 }
793 
794 //////////////////////////////////////////////////////////////////////////////////////////
795 void
markPoint(std::size_t u,std::size_t v,Vector3ub fg_color,Vector3ub bg_color,double radius,const std::string & layer_id,double opacity)796 pcl::visualization::ImageViewer::markPoint (
797     std::size_t u, std::size_t v, Vector3ub fg_color, Vector3ub bg_color, double radius,
798     const std::string &layer_id, double opacity)
799 {
800   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
801   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
802   if (am_it == layer_map_.end ())
803   {
804     PCL_DEBUG ("[pcl::visualization::ImageViewer::markPoint] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
805     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
806   }
807 
808   vtkSmartPointer<context_items::Point> point = vtkSmartPointer<context_items::Point>::New ();
809   point->setColors (fg_color[0], fg_color[1], fg_color[2]);
810   point->setOpacity (opacity);
811 
812   vtkSmartPointer<context_items::Disk> disk = vtkSmartPointer<context_items::Disk>::New ();
813   disk->setColors (bg_color[0], bg_color[1], bg_color[2]);
814   disk->setOpacity (opacity);
815 
816   point->set (static_cast<float> (u), static_cast<float> (v));
817   disk->set (static_cast<float> (u), static_cast<float> (v), static_cast<float> (radius));
818 
819   am_it->actor->GetScene ()->AddItem (disk);
820   am_it->actor->GetScene ()->AddItem (point);
821 }
822 
823 //////////////////////////////////////////////////////////////////////////////////////////
824 void
markPoints(const std::vector<int> & uv,Vector3ub fg_color,Vector3ub bg_color,double size,const std::string & layer_id,double opacity)825 pcl::visualization::ImageViewer::markPoints (
826     const std::vector<int>& uv, Vector3ub fg_color, Vector3ub bg_color, double size,
827     const std::string &layer_id, double opacity)
828 {
829   if (uv.empty ())
830     return;
831 
832   std::vector<float> float_uv (uv.size ());
833   for (std::size_t i = 0; i < uv.size (); ++i)
834     float_uv[i] = static_cast<float> (uv[i]);
835   return (markPoints (float_uv, fg_color, bg_color, size, layer_id, opacity));
836 }
837 
838 //////////////////////////////////////////////////////////////////////////////////////////
839 void
markPoints(const std::vector<float> & uv,Vector3ub fg_color,Vector3ub bg_color,double size,const std::string & layer_id,double opacity)840 pcl::visualization::ImageViewer::markPoints (
841     const std::vector<float>& uv, Vector3ub fg_color, Vector3ub bg_color, double size,
842     const std::string &layer_id, double opacity)
843 {
844   if (uv.empty ())
845     return;
846 
847   // Check to see if this ID entry already exists (has it been already added to the visualizer?)
848   LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
849   if (am_it == layer_map_.end ())
850   {
851     PCL_DEBUG ("[pcl::visualization::ImageViewer::markPoint] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
852     am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
853   }
854 
855   vtkSmartPointer<context_items::Markers> markers = vtkSmartPointer<context_items::Markers>::New ();
856   markers->setOpacity (opacity);
857   markers->set (uv);
858   markers->setSize (size);
859   markers->setColors (bg_color[0], bg_color[1], bg_color[2]);
860   markers->setPointColors (fg_color[0], fg_color[1], fg_color[2]);
861   am_it->actor->GetScene ()->AddItem (markers);
862 }
863 
864 //////////////////////////////////////////////////////////////////////////////////////////
865 void
render()866 pcl::visualization::ImageViewer::render ()
867 {
868   win_->Render ();
869   for(auto &i : image_data_)
870     delete [] i;
871   image_data_.clear ();
872 }
873 
874 //////////////////////////////////////////////////////////////////////////////////////////
875 void
convertIntensityCloudToUChar(const pcl::PointCloud<pcl::Intensity> & cloud,boost::shared_array<unsigned char> data)876 pcl::visualization::ImageViewer::convertIntensityCloudToUChar (
877     const pcl::PointCloud<pcl::Intensity> &cloud,
878     boost::shared_array<unsigned char> data)
879 {
880   int j = 0;
881   for (const auto &point : cloud.points)
882   {
883     data[j++] = static_cast <unsigned char> (point.intensity * 255);
884   }
885 }
886 
887 //////////////////////////////////////////////////////////////////////////////////////////
888 void
convertIntensityCloud8uToUChar(const pcl::PointCloud<pcl::Intensity8u> & cloud,boost::shared_array<unsigned char> data)889 pcl::visualization::ImageViewer::convertIntensityCloud8uToUChar (
890     const pcl::PointCloud<pcl::Intensity8u> &cloud,
891     boost::shared_array<unsigned char> data)
892 {
893   int j = 0;
894   for (const auto &point : cloud.points)
895     data[j++] = static_cast<unsigned char> (point.intensity);
896 }
897 
898 //////////////////////////////////////////////////////////////////////////////////////////
899 //////////////////////////////////////////////////////////////////////////////////////////
900 //////////////////////////////////////////////////////////////////////////////////////////
ImageViewerInteractorStyle()901 pcl::visualization::ImageViewerInteractorStyle::ImageViewerInteractorStyle ()
902 {
903 }
904 
905 //////////////////////////////////////////////////////////////////////////////////////////
906 void
OnChar()907 pcl::visualization::ImageViewerInteractorStyle::OnChar ()
908 {
909   FindPokedRenderer (Interactor->GetEventPosition ()[0], Interactor->GetEventPosition ()[1]);
910 
911   Superclass::OnChar();
912 }
913 
914 //////////////////////////////////////////////////////////////////////////////////////////
915 void
adjustCamera(vtkImageData * image,vtkRenderer * ren)916 pcl::visualization::ImageViewerInteractorStyle::adjustCamera (
917     vtkImageData *image, vtkRenderer *ren)
918 {
919   // Set up the background camera to fill the renderer with the image
920   double origin[3], spacing[3];
921   int extent[6];
922   image->GetOrigin  (origin);
923   image->GetSpacing (spacing);
924   image->GetExtent  (extent);
925 
926   vtkCamera* camera = ren->GetActiveCamera ();
927   double xc = origin[0] + 0.5 * (extent[0] + extent[1]) * spacing[0];
928   double yc = origin[1] + 0.5 * (extent[2] + extent[3]) * spacing[1];
929   double yd = (extent[3] - extent[2] + 1) * spacing[1];
930   double d = camera->GetDistance ();
931   camera->SetParallelScale (0.5 * yd);
932   camera->SetFocalPoint (xc, yc, 0.0);
933   camera->SetPosition (xc, yc, d);
934 }
935 
936 //////////////////////////////////////////////////////////////////////////////////////////
937 void
adjustCamera(vtkRenderer * ren)938 pcl::visualization::ImageViewerInteractorStyle::adjustCamera (vtkRenderer *ren)
939 {
940   // Set up the background camera to fill the renderer with the image
941   vtkCamera* camera = ren->GetActiveCamera ();
942   int *wh = ren->GetRenderWindow ()->GetSize ();
943   double xc = static_cast<double> (wh[0]) / 2.0,
944          yc = static_cast<double> (wh[1]) / 2.0,
945          yd = static_cast<double> (wh[1]),
946          d = 3.346065;
947   camera->SetParallelScale (0.5 * yd);
948   camera->SetFocalPoint (xc, yc, 0.0);
949   camera->SetPosition (xc, yc, d);
950 }
951 
952 //////////////////////////////////////////////////////////////////////////////////////////
953 void
OnLeftButtonDown()954 pcl::visualization::ImageViewerInteractorStyle::OnLeftButtonDown ()
955 {
956   int x = Interactor->GetEventPosition ()[0];
957   int y = Interactor->GetEventPosition ()[1];
958 
959   FindPokedRenderer (x, y);
960   if (!CurrentRenderer)
961     return;
962 
963   // Redefine this button to handle window/level
964   GrabFocus (this->EventCallbackCommand);
965   // If shift is held down, do nothing
966   if (!this->Interactor->GetShiftKey() && !this->Interactor->GetControlKey())
967   {
968     WindowLevelStartPosition[0] = x;
969     WindowLevelStartPosition[1] = y;
970     StartWindowLevel ();
971   }
972   else if (Interactor->GetShiftKey ())
973     return;
974   // If ctrl is held down in slicing mode, do nothing
975   else if (Interactor->GetControlKey ())
976     return;
977   // The rest of the button + key combinations remain the same
978   else
979     Superclass::OnLeftButtonDown ();
980 }
981 
982 //////////////////////////////////////////////////////////////////////////////////////////
983 void
setWindowTitle(const std::string & name)984 pcl::visualization::ImageViewer::setWindowTitle (const std::string& name)
985 {
986   win_->SetWindowName (name.c_str ());
987 }
988 
989 //////////////////////////////////////////////////////////////////////////////////////////
990 void
setPosition(int x,int y)991 pcl::visualization::ImageViewer::setPosition (int x, int y)
992 {
993   win_->SetPosition (x, y);
994 }
995 
996 //////////////////////////////////////////////////////////////////////////////////////////
997 int*
getSize()998 pcl::visualization::ImageViewer::getSize ()
999 {
1000   return (win_->GetSize ());
1001 }
1002 
1003 //////////////////////////////////////////////////////////////////////////////////////////
1004 void
setSize(int xw,int yw)1005 pcl::visualization::ImageViewer::setSize (int xw, int yw)
1006 {
1007   win_->SetSize (xw, yw);
1008 }
1009 
1010 //////////////////////////////////////////////////////////////////////////////////////////
1011 namespace pcl
1012 {
1013   namespace visualization
1014   {
1015     vtkStandardNewMacro (ImageViewerInteractorStyle);
1016   }
1017 }
1018 
1019