1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                           License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19//   * Redistribution's of source code must retain the above copyright notice,
20//     this list of conditions and the following disclaimer.
21//
22//   * Redistribution's in binary form must reproduce the above copyright notice,
23//     this list of conditions and the following disclaimer in the documentation
24//     and/or other materials provided with the distribution.
25//
26//   * The name of the copyright holders may not be used to endorse or promote products
27//     derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40// Authors:
41//  * Ozan Tonkal, ozantonkal@gmail.com
42//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
43//
44//M*/
45
46#include "precomp.hpp"
47
48namespace cv { namespace viz
49{
50    vtkStandardNewMacro(vtkVizInteractorStyle)
51}}
52
53//////////////////////////////////////////////////////////////////////////////////////////////
54
55cv::viz::vtkVizInteractorStyle::vtkVizInteractorStyle()
56{
57    FlyMode = false;
58    MotionFactor = 10.0;
59
60    keyboardCallback_ = 0;
61    keyboard_callback_cookie_ = 0;
62
63    mouseCallback_ = 0;
64    mouse_callback_cookie_ = 0;
65
66    // Set windows size (width, height) to unknown (-1)
67    win_size_ = Vec2i(-1, -1);
68    win_pos_ = Vec2i(0, 0);
69    max_win_size_ = Vec2i(-1, -1);
70
71    stereo_anaglyph_redblue_ = true;
72
73    //from fly
74    KeysDown     = 0;
75    UseTimers    = 1;
76
77    DiagonalLength           = 1.0;
78    MotionStepSize           = 1.0/100.0;
79    MotionUserScale          = 1.0;  // +/- key adjustment
80    MotionAccelerationFactor = 10.0;
81    AngleStepSize            = 1.0;
82}
83
84cv::viz::vtkVizInteractorStyle::~vtkVizInteractorStyle() {}
85
86//////////////////////////////////////////////////////////////////////////////////////////////
87void cv::viz::vtkVizInteractorStyle::saveScreenshot(const String &file)
88{
89    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
90
91    vtkSmartPointer<vtkWindowToImageFilter> wif = vtkSmartPointer<vtkWindowToImageFilter>::New();
92    wif->SetInput(Interactor->GetRenderWindow());
93
94    vtkSmartPointer<vtkPNGWriter> snapshot_writer = vtkSmartPointer<vtkPNGWriter>::New();
95    snapshot_writer->SetInputConnection(wif->GetOutputPort());
96    snapshot_writer->SetFileName(file.c_str());
97    snapshot_writer->Write();
98
99    cout << "Screenshot successfully captured (" << file.c_str() << ")" << endl;
100}
101
102//////////////////////////////////////////////////////////////////////////////////////////////
103
104void cv::viz::vtkVizInteractorStyle::exportScene(const String &file)
105{
106    vtkSmartPointer<vtkExporter> exporter;
107    if (file.size() > 5 && file.substr(file.size() - 5) == ".vrml")
108    {
109        exporter = vtkSmartPointer<vtkVRMLExporter>::New();
110        vtkVRMLExporter::SafeDownCast(exporter)->SetFileName(file.c_str());
111    }
112    else
113    {
114        exporter = vtkSmartPointer<vtkOBJExporter>::New();
115        vtkOBJExporter::SafeDownCast(exporter)->SetFilePrefix(file.c_str());
116    }
117
118    exporter->SetInput(Interactor->GetRenderWindow());
119    exporter->Write();
120
121    cout << "Scene successfully exported (" << file.c_str() << ")" << endl;
122}
123
124void cv::viz::vtkVizInteractorStyle::exportScene()
125{
126    // Export scene as in obj or vrml format
127    String format = Interactor->GetAltKey() ? "scene-%d.vrml" : "scene-%d";
128    exportScene(cv::format(format.c_str(), (unsigned int)time(0)));
129}
130
131//////////////////////////////////////////////////////////////////////////////////////////////
132
133void cv::viz::vtkVizInteractorStyle::changePointsSize(float delta)
134{
135    vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
136    vtkCollectionSimpleIterator ait;
137
138    for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
139        for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
140        {
141            vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
142            float psize = apart->GetProperty()->GetPointSize() + delta;
143            psize = std::max(1.f, std::min(63.f, psize));
144            apart->GetProperty()->SetPointSize(psize);
145        }
146}
147
148void cv::viz::vtkVizInteractorStyle::setRepresentationToPoints()
149{
150    vtkSmartPointer<vtkActorCollection> ac = CurrentRenderer->GetActors();
151    vtkCollectionSimpleIterator ait;
152    for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); )
153        for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); )
154        {
155            vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp());
156            apart->GetProperty()->SetRepresentationToPoints();
157        }
158}
159
160//////////////////////////////////////////////////////////////////////////////////////////////
161
162void cv::viz::vtkVizInteractorStyle::printCameraParams()
163{
164    vtkSmartPointer<vtkCamera> cam = Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
165
166    Vec2d clip(cam->GetClippingRange());
167    Vec3d focal(cam->GetFocalPoint()), pos(cam->GetPosition()), view(cam->GetViewUp());
168    Vec2i win_pos(Interactor->GetRenderWindow()->GetPosition());
169    Vec2i win_size(Interactor->GetRenderWindow()->GetSize());
170    double angle = cam->GetViewAngle () / 180.0 * CV_PI;
171
172    String data = cv::format("clip(%f,%f) focal(%f,%f,%f) pos(%f,%f,%f) view(%f,%f,%f) angle(%f) winsz(%d,%d) winpos(%d,%d)",
173                             clip[0], clip[1], focal[0], focal[1], focal[2], pos[0], pos[1], pos[2], view[0], view[1], view[2],
174                             angle, win_size[0], win_size[1], win_pos[0], win_pos[1]);
175
176    std::cout << data.c_str() << std::endl;
177}
178
179//////////////////////////////////////////////////////////////////////////////////////////////
180
181void cv::viz::vtkVizInteractorStyle::toggleFullScreen()
182{
183    Vec2i screen_size(Interactor->GetRenderWindow()->GetScreenSize());
184    Vec2i win_size(Interactor->GetRenderWindow()->GetSize());
185
186    // Is window size = max?
187    if (win_size == max_win_size_)
188    {
189        Interactor->GetRenderWindow()->SetSize(win_size_.val);
190        Interactor->GetRenderWindow()->SetPosition(win_pos_.val);
191        Interactor->Render();
192    }
193    // Set to max
194    else
195    {
196        win_pos_ = Vec2i(Interactor->GetRenderWindow()->GetPosition());
197        win_size_ = win_size;
198
199        Interactor->GetRenderWindow()->SetSize(screen_size.val);
200        Interactor->Render();
201        max_win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize());
202    }
203}
204
205//////////////////////////////////////////////////////////////////////////////////////////////
206
207void cv::viz::vtkVizInteractorStyle::resetViewerPose()
208{
209    WidgetActorMap::iterator it = widget_actor_map_->begin();
210    // it might be that some actors don't have a valid transformation set -> we skip them to avoid a seg fault.
211    for (; it != widget_actor_map_->end();  ++it)
212    {
213        vtkProp3D * actor = vtkProp3D::SafeDownCast(it->second);
214        if (actor && actor->GetUserMatrix())
215            break;
216    }
217
218    vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
219
220    // if a valid transformation was found, use it otherwise fall back to default view point.
221    if (it != widget_actor_map_->end())
222    {
223        vtkMatrix4x4* m = vtkProp3D::SafeDownCast(it->second)->GetUserMatrix();
224
225        cam->SetFocalPoint(m->GetElement(0, 3) - m->GetElement(0, 2),
226                           m->GetElement(1, 3) - m->GetElement(1, 2),
227                           m->GetElement(2, 3) - m->GetElement(2, 2));
228
229        cam->SetViewUp  (m->GetElement(0, 1), m->GetElement(1, 1), m->GetElement(2, 1));
230        cam->SetPosition(m->GetElement(0, 3), m->GetElement(1, 3), m->GetElement(2, 3));
231    }
232    else
233    {
234        cam->SetPosition(0, 0, 0);
235        cam->SetFocalPoint(0, 0, 1);
236        cam->SetViewUp(0, -1, 0);
237    }
238
239    // go to the next actor for the next key-press event.
240    if (it != widget_actor_map_->end())
241        ++it;
242    else
243        it = widget_actor_map_->begin();
244
245    CurrentRenderer->SetActiveCamera(cam);
246    CurrentRenderer->ResetCameraClippingRange();
247    Interactor->Render();
248}
249
250//////////////////////////////////////////////////////////////////////////////////////////////
251
252void cv::viz::vtkVizInteractorStyle::toggleStereo()
253{
254    vtkSmartPointer<vtkRenderWindow> window = Interactor->GetRenderWindow();
255    if (!window->GetStereoRender())
256    {
257        static Vec2i red_blue(4, 3), magenta_green(2, 5);
258        window->SetAnaglyphColorMask (stereo_anaglyph_redblue_ ? red_blue.val : magenta_green.val);
259        stereo_anaglyph_redblue_ = !stereo_anaglyph_redblue_;
260    }
261    window->SetStereoRender(!window->GetStereoRender());
262    Interactor->Render();
263
264}
265
266//////////////////////////////////////////////////////////////////////////////////////////////
267
268void cv::viz::vtkVizInteractorStyle::printHelp()
269{
270    std::cout << "| Help:\n"
271                 "-------\n"
272                 "          p, P   : switch to a point-based representation\n"
273                 "          w, W   : switch to a wireframe-based representation (where available)\n"
274                 "          s, S   : switch to a surface-based representation (where available)\n"
275                 "\n"
276                 "          j, J   : take a .PNG snapshot of the current window view\n"
277                 "          k, K   : export scene to Wavefront .obj format\n"
278                 "    ALT + k, K   : export scene to VRML format\n"
279                 "          c, C   : display current camera/window parameters\n"
280                 "          F5     : enable/disable fly mode (changes control style)\n"
281                 "\n"
282                 "          e, E   : exit the interactor\n"
283                 "          q, Q   : stop and call VTK's TerminateApp\n"
284                 "\n"
285                 "           +/-   : increment/decrement overall point size\n"
286                 "     +/- [+ ALT] : zoom in/out \n"
287                 "\n"
288                 "    r, R [+ ALT] : reset camera [to viewpoint = {0, 0, 0} -> center_{x, y, z}]\n"
289                 "\n"
290                 "    ALT + s, S   : turn stereo mode on/off\n"
291                 "    ALT + f, F   : switch between maximized window mode and original size\n"
292                 "\n"
293              << std::endl;
294}
295
296//////////////////////////////////////////////////////////////////////////////////////////////
297void cv::viz::vtkVizInteractorStyle::zoomIn()
298{
299    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
300    // Zoom in
301    StartDolly();
302    double factor = 10.0 * 0.2 * .5;
303    Dolly(std::pow(1.1, factor));
304    EndDolly();
305}
306
307//////////////////////////////////////////////////////////////////////////////////////////////
308void cv::viz::vtkVizInteractorStyle::zoomOut()
309{
310    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
311    // Zoom out
312    StartDolly();
313    double factor = 10.0 * -0.2 * .5;
314    Dolly(std::pow(1.1, factor));
315    EndDolly();
316}
317
318//////////////////////////////////////////////////////////////////////////////////////////////
319void cv::viz::vtkVizInteractorStyle::OnChar()
320{
321    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
322
323    String key(Interactor->GetKeySym());
324    if (key.find("XF86ZoomIn") != String::npos)
325        zoomIn();
326    else if (key.find("XF86ZoomOut") != String::npos)
327        zoomOut();
328
329    switch (Interactor->GetKeyCode())
330    {
331//    // All of the options below simply exit
332//    case 'l': case 'L': case 'j': case 'J': case 'c': case 'C': case 'q': case 'Q':
333//    case 'f': case 'F': case 'g': case 'G': case 'o': case 'O': case 'u': case 'U':
334    case 'p': case 'P':
335        break;
336
337    case '+':
338        if (FlyMode)
339            MotionUserScale = std::min(16.0, MotionUserScale*2.0);
340        break;
341    case '-':
342        if (FlyMode)
343            MotionUserScale = std::max(MotionUserScale * 0.5, 0.0625);
344        break;
345
346    case 'r': case 'R': case 's': case 'S':
347        if (!Interactor->GetAltKey())
348            Superclass::OnChar();
349        break;
350    default:
351        Superclass::OnChar();
352        break;
353    }
354}
355
356//////////////////////////////////////////////////////////////////////////////////////////////
357void cv::viz::vtkVizInteractorStyle::registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie)
358{
359    mouseCallback_ = callback;
360    mouse_callback_cookie_ = cookie;
361}
362
363void cv::viz::vtkVizInteractorStyle::registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void *cookie)
364{
365    keyboardCallback_ = callback;
366    keyboard_callback_cookie_ = cookie;
367}
368
369//////////////////////////////////////////////////////////////////////////////////////////////
370int cv::viz::vtkVizInteractorStyle::getModifiers()
371{
372    int modifiers = KeyboardEvent::NONE;
373
374    if (Interactor->GetAltKey())
375        modifiers |= KeyboardEvent::ALT;
376
377    if (Interactor->GetControlKey())
378        modifiers |= KeyboardEvent::CTRL;
379
380    if (Interactor->GetShiftKey())
381        modifiers |= KeyboardEvent::SHIFT;
382    return modifiers;
383}
384
385//////////////////////////////////////////////////////////////////////////////////////////////
386void cv::viz::vtkVizInteractorStyle::OnKeyDown()
387{
388    FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]);
389
390    String key(Interactor->GetKeySym());
391    if (key.find("XF86ZoomIn") != String::npos)
392        zoomIn();
393    else if (key.find("XF86ZoomOut") != String::npos)
394        zoomOut();
395    else if (key.find("F5") != String::npos)
396    {
397        FlyMode = !FlyMode;
398        std::cout << (FlyMode ? "Fly mode: on" : "Fly mode: off") << std::endl;
399    }
400
401    // Save the initial windows width/height
402    if (win_size_[0] == -1 || win_size_[1] == -1)
403        win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize());
404
405    switch (Interactor->GetKeyCode())
406    {
407    case 'a': case 'A' : KeysDown |=16; break;
408    case 'z': case 'Z' : KeysDown |=32; break;
409    case 'h': case 'H' : printHelp();   break;
410    case 'p': case 'P' : setRepresentationToPoints(); break;
411    case 'k': case 'K' : exportScene(); break;
412    case 'j': case 'J' : saveScreenshot(cv::format("screenshot-%d.png", (unsigned int)time(0))); break;
413    case 'c': case 'C' : printCameraParams(); break;
414    case '=':           zoomIn();            break;
415    case 43:        // KEY_PLUS
416    {
417        if (FlyMode)
418            break;
419        if (Interactor->GetAltKey())
420            zoomIn();
421        else
422            changePointsSize(+1.f);
423        break;
424    }
425    case 45:        // KEY_MINUS
426    {
427        if (FlyMode)
428            break;
429        if (Interactor->GetAltKey())
430            zoomOut();
431        else
432           changePointsSize(-1.f);
433        break;
434    }
435        // Switch between maximize and original window size
436    case 'f': case 'F':
437    {
438        if (Interactor->GetAltKey())
439            toggleFullScreen();
440        break;
441    }
442        // 's'/'S' w/out ALT
443    case 's': case 'S':
444    {
445        if (Interactor->GetAltKey())
446            toggleStereo();
447        break;
448    }
449
450    case 'o': case 'O':
451    {
452        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
453        cam->SetParallelProjection(!cam->GetParallelProjection());
454        Interactor->Render();
455        break;
456    }
457
458    // Overwrite the camera reset
459    case 'r': case 'R':
460    {
461        if (Interactor->GetAltKey())
462            resetViewerPose();
463        break;
464    }
465    case 'q': case 'Q':
466        Interactor->ExitCallback(); return;
467    default:
468        Superclass::OnKeyDown(); break;
469    }
470
471    KeyboardEvent event(KeyboardEvent::KEY_DOWN, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers());
472    if (keyboardCallback_)
473        keyboardCallback_(event, keyboard_callback_cookie_);
474
475    if (FlyMode && (KeysDown & (32+16)) == (32+16))
476    {
477        if (State == VTKIS_FORWARDFLY || State == VTKIS_REVERSEFLY)
478            StopState();
479    }
480    else if (FlyMode && (KeysDown & 32) == 32)
481    {
482        if (State == VTKIS_FORWARDFLY)
483            StopState();
484
485        if (State == VTKIS_NONE)
486            StartState(VTKIS_REVERSEFLY);
487    }
488    else if (FlyMode && (KeysDown & 16) == 16)
489    {
490        if (State == VTKIS_REVERSEFLY)
491            StopState();
492
493        if (State == VTKIS_NONE)
494            StartState(VTKIS_FORWARDFLY);
495    }
496
497    Interactor->Render();
498}
499
500//////////////////////////////////////////////////////////////////////////////////////////////
501void cv::viz::vtkVizInteractorStyle::OnKeyUp()
502{
503    KeyboardEvent event(KeyboardEvent::KEY_UP, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers());
504    if (keyboardCallback_)
505        keyboardCallback_(event, keyboard_callback_cookie_);
506
507    switch (Interactor->GetKeyCode())
508    {
509    case 'a': case 'A' : KeysDown &= ~16; break;
510    case 'z': case 'Z' : KeysDown &= ~32; break;
511    }
512
513    if (State == VTKIS_FORWARDFLY && (KeysDown & 16) == 0)
514        StopState();
515
516    if (State == VTKIS_REVERSEFLY && (KeysDown & 32) == 0)
517        StopState();
518
519    Superclass::OnKeyUp();
520}
521
522//////////////////////////////////////////////////////////////////////////////////////////////
523void cv::viz::vtkVizInteractorStyle::OnMouseMove()
524{
525    Vec2i p(Interactor->GetEventPosition());
526    MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, p, getModifiers());
527    if (mouseCallback_)
528        mouseCallback_(event, mouse_callback_cookie_);
529
530    FindPokedRenderer(p[0], p[1]);
531
532    if (State == VTKIS_ROTATE || State == VTKIS_PAN || State == VTKIS_DOLLY || State == VTKIS_SPIN)
533    {
534        switch (State)
535        {
536        case VTKIS_ROTATE: Rotate(); break;
537        case VTKIS_PAN:    Pan();    break;
538        case VTKIS_DOLLY:  Dolly();  break;
539        case VTKIS_SPIN:   Spin();   break;
540        }
541
542        InvokeEvent(vtkCommand::InteractionEvent, NULL);
543    }
544
545    if (State == VTKIS_FORWARDFLY || State == VTKIS_REVERSEFLY)
546    {
547        vtkCamera *cam = CurrentRenderer->GetActiveCamera();
548        Vec2i thispos(Interactor->GetEventPosition());
549        Vec2i lastpos(Interactor->GetLastEventPosition());
550
551        // we want to steer by an amount proportional to window viewangle and size
552        // compute dx and dy increments relative to last mouse click
553        Vec2i size(Interactor->GetSize());
554        double scalefactor = 5*cam->GetViewAngle()/size[0];
555
556        double dx = - (thispos[0] - lastpos[0])*scalefactor*AngleStepSize;
557        double dy =   (thispos[1] - lastpos[1])*scalefactor*AngleStepSize;
558
559        // Temporary until I get smooth flight working
560        DeltaPitch = dy;
561        DeltaYaw = dx;
562
563        InvokeEvent(vtkCommand::InteractionEvent, NULL);
564    }
565}
566
567//////////////////////////////////////////////////////////////////////////////////////////////
568void cv::viz::vtkVizInteractorStyle::OnLeftButtonDown()
569{
570    Vec2i p(Interactor->GetEventPosition());
571    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
572    MouseEvent event(type, MouseEvent::LeftButton, p, getModifiers());
573    if (mouseCallback_)
574        mouseCallback_(event, mouse_callback_cookie_);
575
576    FindPokedRenderer(p[0], p[1]);
577    if (!CurrentRenderer)
578        return;
579
580    GrabFocus(EventCallbackCommand);
581
582    if (FlyMode)
583    {
584        if(State == VTKIS_REVERSEFLY)
585            State = VTKIS_FORWARDFLY;
586        else
587        {
588            SetupMotionVars();
589            if (State == VTKIS_NONE)
590                StartState(VTKIS_FORWARDFLY);
591        }
592    }
593    else
594    {
595        if (Interactor->GetShiftKey())
596        {
597            if (Interactor->GetControlKey())
598                StartDolly();
599            else
600                StartPan();
601        }
602        else
603        {
604            if (Interactor->GetControlKey())
605                StartSpin();
606            else
607                StartRotate();
608        }
609    }
610}
611
612//////////////////////////////////////////////////////////////////////////////////////////////
613void cv::viz::vtkVizInteractorStyle::OnLeftButtonUp()
614{
615    Vec2i p(Interactor->GetEventPosition());
616    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::LeftButton, p, getModifiers());
617    if (mouseCallback_)
618        mouseCallback_(event, mouse_callback_cookie_);
619
620    switch (State)
621    {
622    case VTKIS_DOLLY:      EndDolly();  break;
623    case VTKIS_PAN:        EndPan();    break;
624    case VTKIS_SPIN:       EndSpin();   break;
625    case VTKIS_ROTATE:     EndRotate(); break;
626    case VTKIS_FORWARDFLY: StopState(); break;
627    }
628
629    if (Interactor )
630        ReleaseFocus();
631}
632
633//////////////////////////////////////////////////////////////////////////////////////////////
634void cv::viz::vtkVizInteractorStyle::OnMiddleButtonDown()
635{
636    Vec2i p(Interactor->GetEventPosition());
637    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
638    MouseEvent event(type, MouseEvent::MiddleButton, p, getModifiers());
639    if (mouseCallback_)
640        mouseCallback_(event, mouse_callback_cookie_);
641
642    FindPokedRenderer(p[0], p[1]);
643    if (!CurrentRenderer)
644        return;
645
646    GrabFocus(EventCallbackCommand);
647    StartPan();
648}
649
650//////////////////////////////////////////////////////////////////////////////////////////////
651void cv::viz::vtkVizInteractorStyle::OnMiddleButtonUp()
652{
653    Vec2i p(Interactor->GetEventPosition());
654    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::MiddleButton, p, getModifiers());
655    if (mouseCallback_)
656        mouseCallback_(event, mouse_callback_cookie_);
657
658    if (State == VTKIS_PAN)
659    {
660        EndPan();
661        if (Interactor)
662            ReleaseFocus();
663    }
664}
665
666//////////////////////////////////////////////////////////////////////////////////////////////
667void cv::viz::vtkVizInteractorStyle::OnRightButtonDown()
668{
669    Vec2i p(Interactor->GetEventPosition());
670    MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick;
671    MouseEvent event(type, MouseEvent::RightButton, p, getModifiers());
672    if (mouseCallback_)
673        mouseCallback_(event, mouse_callback_cookie_);
674
675    FindPokedRenderer(p[0], p[1]);
676    if (!CurrentRenderer)
677        return;
678
679    GrabFocus(EventCallbackCommand);
680
681    if (FlyMode)
682    {
683        if (State == VTKIS_FORWARDFLY)
684            State = VTKIS_REVERSEFLY;
685        else
686        {
687            SetupMotionVars();
688            if (State == VTKIS_NONE)
689                StartState(VTKIS_REVERSEFLY);
690        }
691
692    }
693    else
694        StartDolly();
695}
696
697
698//////////////////////////////////////////////////////////////////////////////////////////////
699void cv::viz::vtkVizInteractorStyle::OnRightButtonUp()
700{
701    Vec2i p(Interactor->GetEventPosition());
702    MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::RightButton, p, getModifiers());
703    if (mouseCallback_)
704        mouseCallback_(event, mouse_callback_cookie_);
705
706    if(State == VTKIS_DOLLY)
707    {
708        EndDolly();
709        if (Interactor)
710            ReleaseFocus();
711    }
712
713    if (State == VTKIS_REVERSEFLY)
714    {
715        StopState();
716        if (Interactor)
717            ReleaseFocus();
718    }
719}
720
721//////////////////////////////////////////////////////////////////////////////////////////////
722void cv::viz::vtkVizInteractorStyle::OnMouseWheelForward()
723{
724    Vec2i p(Interactor->GetEventPosition());
725    MouseEvent event(MouseEvent::MouseScrollUp, MouseEvent::VScroll, p, getModifiers());
726    if (mouseCallback_)
727        mouseCallback_(event, mouse_callback_cookie_);
728    if (Interactor->GetRepeatCount() && mouseCallback_)
729        mouseCallback_(event, mouse_callback_cookie_);
730
731    if (Interactor->GetAltKey())
732    {
733        // zoom
734        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
735        double opening_angle = cam->GetViewAngle();
736        if (opening_angle > 15.0)
737            opening_angle -= 1.0;
738
739        cam->SetViewAngle(opening_angle);
740        cam->Modified();
741        CurrentRenderer->ResetCameraClippingRange();
742        CurrentRenderer->Modified();
743        Interactor->Render();
744    }
745    else
746    {
747        FindPokedRenderer(p[0], p[1]);
748        if (!CurrentRenderer)
749            return;
750
751        GrabFocus(EventCallbackCommand);
752        StartDolly();
753        Dolly(pow(1.1, MotionFactor * 0.2 * MouseWheelMotionFactor));
754        EndDolly();
755        ReleaseFocus();
756    }
757}
758
759//////////////////////////////////////////////////////////////////////////////////////////////
760void cv::viz::vtkVizInteractorStyle::OnMouseWheelBackward()
761{
762    Vec2i p(Interactor->GetEventPosition());
763    MouseEvent event(MouseEvent::MouseScrollDown, MouseEvent::VScroll, p, getModifiers());
764    if (mouseCallback_)
765        mouseCallback_(event, mouse_callback_cookie_);
766
767    if (Interactor->GetRepeatCount() && mouseCallback_)
768        mouseCallback_(event, mouse_callback_cookie_);
769
770    if (Interactor->GetAltKey())
771    {
772        // zoom
773        vtkSmartPointer<vtkCamera> cam = CurrentRenderer->GetActiveCamera();
774        double opening_angle = cam->GetViewAngle();
775        if (opening_angle < 170.0)
776            opening_angle += 1.0;
777
778        cam->SetViewAngle(opening_angle);
779        cam->Modified();
780        CurrentRenderer->ResetCameraClippingRange();
781        CurrentRenderer->Modified();
782        Interactor->Render();
783    }
784    else
785    {
786        FindPokedRenderer(p[0], p[1]);
787        if (!CurrentRenderer)
788            return;
789
790        GrabFocus(EventCallbackCommand);
791        StartDolly();
792        Dolly(pow(1.1, MotionFactor * -0.2 * MouseWheelMotionFactor));
793        EndDolly();
794        ReleaseFocus();
795    }
796}
797
798//////////////////////////////////////////////////////////////////////////////////////////////
799void cv::viz::vtkVizInteractorStyle::OnTimer()
800{
801    if  (State == VTKIS_FORWARDFLY || State == VTKIS_REVERSEFLY)
802        Fly();
803
804    Interactor->Render();
805}
806
807//////////////////////////////////////////////////////////////////////////////////////////////
808
809void cv::viz::vtkVizInteractorStyle::Rotate()
810{
811    if (!CurrentRenderer)
812        return;
813
814    Vec2i dxy = Vec2i(Interactor->GetEventPosition()) - Vec2i(Interactor->GetLastEventPosition());
815    Vec2i size(CurrentRenderer->GetRenderWindow()->GetSize());
816
817    double delta_elevation = -20.0 / size[1];
818    double delta_azimuth   = -20.0 / size[0];
819
820    double rxf = dxy[0] * delta_azimuth * MotionFactor;
821    double ryf = dxy[1] * delta_elevation * MotionFactor;
822
823    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
824    camera->Azimuth(rxf);
825    camera->Elevation(ryf);
826    camera->OrthogonalizeViewUp();
827
828    if (AutoAdjustCameraClippingRange)
829        CurrentRenderer->ResetCameraClippingRange();
830
831    if (Interactor->GetLightFollowCamera())
832        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
833
834    Interactor->Render();
835}
836
837//////////////////////////////////////////////////////////////////////////////////////////////
838void cv::viz::vtkVizInteractorStyle::Spin()
839{
840    if (!CurrentRenderer)
841        return;
842
843    vtkRenderWindowInteractor *rwi = Interactor;
844
845    double *center = CurrentRenderer->GetCenter();
846
847    double newAngle = vtkMath::DegreesFromRadians( atan2( rwi->GetEventPosition()[1]     - center[1], rwi->GetEventPosition()[0]     - center[0] ) );
848    double oldAngle = vtkMath::DegreesFromRadians( atan2( rwi->GetLastEventPosition()[1] - center[1], rwi->GetLastEventPosition()[0] - center[0] ) );
849
850    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
851    camera->Roll( newAngle - oldAngle );
852    camera->OrthogonalizeViewUp();
853
854    rwi->Render();
855}
856
857//////////////////////////////////////////////////////////////////////////////////////////////
858void cv::viz::vtkVizInteractorStyle::Pan()
859{
860    if (!CurrentRenderer)
861        return;
862
863    vtkRenderWindowInteractor *rwi = Interactor;
864
865    double viewFocus[4], focalDepth, viewPoint[3];
866    double newPickPoint[4], oldPickPoint[4], motionVector[3];
867
868    // Calculate the focal depth since we'll be using it a lot
869
870    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
871    camera->GetFocalPoint(viewFocus);
872    ComputeWorldToDisplay(viewFocus[0], viewFocus[1], viewFocus[2], viewFocus);
873    focalDepth = viewFocus[2];
874
875    ComputeDisplayToWorld(rwi->GetEventPosition()[0], rwi->GetEventPosition()[1], focalDepth, newPickPoint);
876
877    // Has to recalc old mouse point since the viewport has moved, so can't move it outside the loop
878    ComputeDisplayToWorld(rwi->GetLastEventPosition()[0], rwi->GetLastEventPosition()[1], focalDepth, oldPickPoint);
879
880    // Camera motion is reversed
881    motionVector[0] = oldPickPoint[0] - newPickPoint[0];
882    motionVector[1] = oldPickPoint[1] - newPickPoint[1];
883    motionVector[2] = oldPickPoint[2] - newPickPoint[2];
884
885    camera->GetFocalPoint(viewFocus);
886    camera->GetPosition(viewPoint);
887    camera->SetFocalPoint(motionVector[0] + viewFocus[0], motionVector[1] + viewFocus[1], motionVector[2] + viewFocus[2]);
888    camera->SetPosition(  motionVector[0] + viewPoint[0], motionVector[1] + viewPoint[1], motionVector[2] + viewPoint[2]);
889
890    if (Interactor->GetLightFollowCamera())
891        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
892
893    Interactor->Render();
894}
895
896//////////////////////////////////////////////////////////////////////////////////////////////
897
898void cv::viz::vtkVizInteractorStyle::Dolly()
899{
900    if (!CurrentRenderer)
901        return;
902
903    int dy = Interactor->GetEventPosition()[1] - Interactor->GetLastEventPosition()[1];
904    Dolly(pow(1.1, MotionFactor * dy / CurrentRenderer->GetCenter()[1]));
905}
906
907void cv::viz::vtkVizInteractorStyle::Dolly(double factor)
908{
909    if (!CurrentRenderer)
910        return;
911
912    vtkCamera *camera = CurrentRenderer->GetActiveCamera();
913    if (camera->GetParallelProjection())
914        camera->SetParallelScale(camera->GetParallelScale() / factor);
915    else
916    {
917        camera->Dolly(factor);
918        if (AutoAdjustCameraClippingRange)
919            CurrentRenderer->ResetCameraClippingRange();
920    }
921
922    if (Interactor->GetLightFollowCamera())
923        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
924
925    Interactor->Render();
926}
927//////////////////////////////////////////////////////////////////////////////////////////////
928
929void cv::viz::vtkVizInteractorStyle::Fly()
930{
931    if (CurrentRenderer == NULL)
932        return;
933
934    if (KeysDown)
935        FlyByKey();
936    else
937        FlyByMouse();
938
939    CurrentRenderer->GetActiveCamera()->OrthogonalizeViewUp();
940
941    if (AutoAdjustCameraClippingRange)
942        CurrentRenderer->ResetCameraClippingRange();
943
944    if (Interactor->GetLightFollowCamera())
945        CurrentRenderer->UpdateLightsGeometryToFollowCamera();
946}
947
948void cv::viz::vtkVizInteractorStyle::SetupMotionVars()
949{
950    Vec6d bounds;
951    CurrentRenderer->ComputeVisiblePropBounds(bounds.val);
952
953    if ( !vtkMath::AreBoundsInitialized(bounds.val) )
954        DiagonalLength = 1.0;
955    else
956        DiagonalLength = norm(Vec3d(bounds[0], bounds[2], bounds[4]) - Vec3d(bounds[1], bounds[3], bounds[5]));
957}
958
959void cv::viz::vtkVizInteractorStyle::MotionAlongVector(const Vec3d& vector, double amount, vtkCamera* cam)
960{
961    // move camera and focus along DirectionOfProjection
962    Vec3d campos = Vec3d(cam->GetPosition())   - amount * vector;
963    Vec3d camfoc = Vec3d(cam->GetFocalPoint()) - amount * vector;
964
965    cam->SetPosition(campos.val);
966    cam->SetFocalPoint(camfoc.val);
967}
968
969void cv::viz::vtkVizInteractorStyle::FlyByMouse()
970{
971    vtkCamera* cam = CurrentRenderer->GetActiveCamera();
972    double speed  = DiagonalLength * MotionStepSize * MotionUserScale;
973    speed = speed * ( Interactor->GetShiftKey() ? MotionAccelerationFactor : 1.0);
974
975    // Sidestep
976    if (Interactor->GetAltKey())
977    {
978        if (DeltaYaw!=0.0)
979        {
980            vtkMatrix4x4 *vtm = cam->GetViewTransformMatrix();
981            Vec3d a_vector(vtm->GetElement(0,0), vtm->GetElement(0,1), vtm->GetElement(0,2));
982
983            MotionAlongVector(a_vector, -DeltaYaw*speed, cam);
984        }
985        if (DeltaPitch!=0.0)
986        {
987            Vec3d a_vector(cam->GetViewUp());
988            MotionAlongVector(a_vector, DeltaPitch*speed, cam);
989        }
990    }
991    else
992    {
993        cam->Yaw(DeltaYaw);
994        cam->Pitch(DeltaPitch);
995        DeltaYaw = 0;
996        DeltaPitch = 0;
997    }
998    //
999    if (!Interactor->GetControlKey())
1000    {
1001        Vec3d a_vector(cam->GetDirectionOfProjection()); // reversed (use -speed)
1002        switch (State)
1003        {
1004        case VTKIS_FORWARDFLY: MotionAlongVector(a_vector, -speed, cam); break;
1005        case VTKIS_REVERSEFLY: MotionAlongVector(a_vector, speed, cam); break;
1006        }
1007    }
1008}
1009
1010void cv::viz::vtkVizInteractorStyle::FlyByKey()
1011{
1012    vtkCamera* cam = CurrentRenderer->GetActiveCamera();
1013
1014    double speed  = DiagonalLength * MotionStepSize * MotionUserScale;
1015    speed = speed * ( Interactor->GetShiftKey() ? MotionAccelerationFactor : 1.0);
1016
1017    // Left and right
1018    if (Interactor->GetAltKey())
1019    { // Sidestep
1020        vtkMatrix4x4 *vtm = cam->GetViewTransformMatrix();
1021        Vec3d a_vector(vtm->GetElement(0,0), vtm->GetElement(0,1), vtm->GetElement(0,2));
1022
1023        if (KeysDown & 1)
1024            MotionAlongVector(a_vector, -speed, cam);
1025
1026        if (KeysDown & 2)
1027            MotionAlongVector(a_vector,  speed, cam);
1028    }
1029    else
1030    {
1031        if (KeysDown & 1)
1032            cam->Yaw( AngleStepSize);
1033
1034        if (KeysDown & 2)
1035            cam->Yaw(-AngleStepSize);
1036    }
1037
1038    // Up and Down
1039    if (Interactor->GetControlKey())
1040    { // Sidestep
1041        Vec3d a_vector = Vec3d(cam->GetViewUp());
1042        if (KeysDown & 4)
1043            MotionAlongVector(a_vector,-speed, cam);
1044
1045        if (KeysDown & 8)
1046            MotionAlongVector(a_vector, speed, cam);
1047    }
1048    else
1049    {
1050        if (KeysDown & 4)
1051            cam->Pitch(-AngleStepSize);
1052
1053        if (KeysDown & 8)
1054            cam->Pitch( AngleStepSize);
1055    }
1056
1057    // forward and backward
1058    Vec3d a_vector(cam->GetDirectionOfProjection());
1059    if (KeysDown & 16)
1060        MotionAlongVector(a_vector, speed, cam);
1061
1062    if (KeysDown & 32)
1063        MotionAlongVector(a_vector,-speed, cam);
1064}
1065
1066//////////////////////////////////////////////////////////////////////////////////////////////
1067
1068void cv::viz::vtkVizInteractorStyle::PrintSelf(ostream& os, vtkIndent indent)
1069{
1070    Superclass::PrintSelf(os, indent);
1071    os << indent << "MotionFactor: " << MotionFactor << "\n";
1072    os << indent << "MotionStepSize: " << MotionStepSize << "\n";
1073    os << indent << "MotionAccelerationFactor: "<< MotionAccelerationFactor << "\n";
1074    os << indent << "AngleStepSize: " << AngleStepSize << "\n";
1075    os << indent << "MotionUserScale: "<< MotionUserScale << "\n";
1076}
1077