imstkVTKInteractorStyle.cpp 10.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*=========================================================================

   Library: iMSTK

   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
   & Imaging in Medicine, Rensselaer Polytechnic Institute.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

20
=========================================================================*/
21

22
// imstk
23
#include "imstkVTKInteractorStyle.h"
24
25
#include "imstkSimulationManager.h"

26
// vtk
27
28
29
30
31
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
32
33
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
34

35
36
namespace imstk
{
37
38
39
40
41
42
43
44
45
46
47
48
49
50
VTKInteractorStyle::VTKInteractorStyle()
{
    m_targetMS = 0.0; // 0 for no wait time
    m_displayFps = false;
    m_lastFpsUpdate = std::chrono::high_resolution_clock::now();
    m_lastFps = 60.0;
    m_fpsActor = vtkTextActor::New();
    m_fpsActor->GetTextProperty()->SetFontSize(60);
    m_fpsActor->SetVisibility(m_displayFps);
}

VTKInteractorStyle::~VTKInteractorStyle()
{
    m_fpsActor->Delete();
51
    this->SetReferenceCount(0);
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
}

void
VTKInteractorStyle::SetCurrentRenderer(vtkRenderer* ren)
{
    // Remove actor if previous renderer
    if(this->CurrentRenderer)
    {
        this->CurrentRenderer->RemoveActor2D(m_fpsActor);
    }

    // Set new current renderer
    vtkBaseInteractorStyle::SetCurrentRenderer(ren);

    // Add actor to current renderer
    this->CurrentRenderer->AddActor2D(m_fpsActor);
}

70
void
71
VTKInteractorStyle::OnTimer()
72
{
Nicholas Milef's avatar
Nicholas Milef committed
73
74
    auto renderer = std::static_pointer_cast<VTKRenderer>(m_simManager->getViewer()->getActiveRenderer());

75
    // Update Camera
Nicholas Milef's avatar
Nicholas Milef committed
76
    renderer->updateSceneCamera(m_simManager->getActiveScene()->getCamera());
77

78
    // Update render delegates
Nicholas Milef's avatar
Nicholas Milef committed
79
    renderer->updateRenderDelegates();
80

81
    // Reset camera clipping range
82
83
    this->CurrentRenderer->ResetCameraClippingRange();

84
85
    // Update framerate value display
    auto now = std::chrono::high_resolution_clock::now();
86
    double fps = 1e6 / (double)std::chrono::duration_cast<std::chrono::microseconds>(now - m_pre).count();
87
88
89
    fps = 0.1 * fps + 0.9 * m_lastFps;
    m_lastFps = fps;
    int t = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_lastFpsUpdate).count();
90
    if (t > 250) //wait 250ms before updating displayed value
91
    {
92
93
94
95
96
97
98
99
100
101
102
103
        std::string fpsVisualStr = "V: " + std::to_string((int)fps);

        std::string fpsPhysicalStr;
        if (m_simManager->getStatus() != SimulationStatus::PAUSED)
        {
            fpsPhysicalStr = "P: " + std::to_string((int)m_simManager->getActiveScene()->getFPS());
        }
        else
        {
            fpsPhysicalStr = "P: PAUSED";
        }
        m_fpsActor->SetInput((fpsVisualStr + std::string(" | ") + fpsPhysicalStr).c_str());
104
105
106
        m_lastFpsUpdate = now;
    }
    m_pre = now;
107

108

109
110
    // Render
    this->Interactor->Render();
111
112
113
114
115
116
117
118
119
120
    m_post = std::chrono::high_resolution_clock::now();

    // Plan next render
    auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(m_post-m_pre).count();
    if (dt < m_targetMS)
    {
        this->Interactor->CreateOneShotTimer(m_targetMS - dt);
    }
    else
    {
121
        this->Interactor->CreateOneShotTimer(1);
122
    }
123

124
    // Call custom behavior
125
126
    if (m_onTimerFunction)
    {
127
        // Call the custom behavior to run on every frame
128
129
        m_onTimerFunction(this);
    }
130
131
}

132
void
133
VTKInteractorStyle::OnChar()
134
{
135
    char key = this->Interactor->GetKeyCode();
136

137
138
139
140
141
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onCharFunctionMap.count(key) &&
       m_onCharFunctionMap.at(key) &&
       m_onCharFunctionMap.at(key)(this))
142
    {
143
        return;
144
    }
145

146
    SimulationStatus status = m_simManager->getStatus();
147

148
    if (key == ' ')
149
    {
150
151
        // pause simulation
        if (status == SimulationStatus::RUNNING)
152
153
154
        {
            m_simManager->pauseSimulation();
        }
155
156
        // play simulation
        else if (status == SimulationStatus::PAUSED)
157
158
159
        {
            m_simManager->runSimulation();
        }
160
161
162
163
        // Launch simulation if inactive
        if (status == SimulationStatus::INACTIVE)
        {
            m_fpsActor->SetVisibility(m_displayFps);
164
            m_simManager->startSimulation(SimulationStatus::RUNNING);
165
166
167
168
169
170
171
        }
    }
    else if (status != SimulationStatus::INACTIVE &&
             (key == 'q' || key == 'Q' || key == 'e' || key == 'E')) // end Simulation
    {
        m_fpsActor->VisibilityOff();
        m_simManager->endSimulation();
172
    }
173
    else if (key == 'd' || key == 'D') // switch rendering mode
174
    {
Nicholas Milef's avatar
Nicholas Milef committed
175
        if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::SIMULATION)
176
        {
Nicholas Milef's avatar
Nicholas Milef committed
177
            m_simManager->getViewer()->setRenderingMode(Renderer::Mode::SIMULATION);
178
179
180
        }
        else
        {
Nicholas Milef's avatar
Nicholas Milef committed
181
            m_simManager->getViewer()->setRenderingMode(Renderer::Mode::DEBUG);
182
183
        }
    }
184
    else if (key == '\u001B') // quit viewer
185
186
    {
        m_simManager->getViewer()->endRenderingLoop();
187
    }
188
    else if (key == 'p' || key == 'P') // switch framerate display
189
190
191
192
193
    {
        m_displayFps = !m_displayFps;
        m_fpsActor->SetVisibility(m_displayFps);
        this->Interactor->Render();
    }
194
195
196
197
    else if (key == 'r' || key == 'R')
    {
        m_simManager->resetSimulation();
    }
198
199
200
}

void
201
VTKInteractorStyle::OnMouseMove()
202
{
203
204
205
206
207
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onMouseMoveFunction &&
       m_onMouseMoveFunction(this))
    {
208
        return;
209
210
211
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
212
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
213
214
215
216
    {
        return;
    }

217
    // Else : use base class interaction
218
219
220
221
    vtkBaseInteractorStyle::OnMouseMove();
}

void
222
VTKInteractorStyle::OnLeftButtonDown()
223
{
224
225
226
227
228
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onLeftButtonDownFunction &&
       m_onLeftButtonDownFunction(this))
    {
229
        return;
230
231
232
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
233
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
234
235
236
237
    {
        return;
    }

238
    // Else : use base class interaction
239
240
241
242
    vtkBaseInteractorStyle::OnLeftButtonDown();
}

void
243
VTKInteractorStyle::OnLeftButtonUp()
244
{
245
246
247
248
249
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onLeftButtonUpFunction &&
       m_onLeftButtonUpFunction(this))
    {
250
        return;
251
252
253
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
254
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
255
256
257
258
    {
        return;
    }

259
    // Else : use base class interaction
260
261
262
263
    vtkBaseInteractorStyle::OnLeftButtonUp();
}

void
264
VTKInteractorStyle::OnMiddleButtonDown()
265
{
266
267
268
269
270
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onMiddleButtonDownFunction &&
       m_onMiddleButtonDownFunction(this))
    {
271
        return;
272
273
274
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
275
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
276
277
278
279
    {
        return;
    }

280
    // Else : use base class interaction
281
282
283
284
    vtkBaseInteractorStyle::OnMiddleButtonDown();
}

void
285
VTKInteractorStyle::OnMiddleButtonUp()
286
{
287
288
289
290
291
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onMiddleButtonUpFunction &&
       m_onMiddleButtonUpFunction(this))
    {
292
        return;
293
294
295
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
296
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
297
298
299
300
    {
        return;
    }

301
    // Else : use base class interaction
302
303
304
305
    vtkBaseInteractorStyle::OnMiddleButtonUp();
}

void
306
VTKInteractorStyle::OnRightButtonDown()
307
{
308
309
310
311
312
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onRightButtonDownFunction &&
       m_onRightButtonDownFunction(this))
    {
313
        return;
314
315
316
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
317
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
318
319
320
321
    {
        return;
    }

322
    // Else : use base class interaction
323
324
325
326
    vtkBaseInteractorStyle::OnRightButtonDown();
}

void
327
VTKInteractorStyle::OnRightButtonUp()
328
{
329
330
331
332
333
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onRightButtonUpFunction &&
       m_onRightButtonUpFunction(this))
    {
334
        return;
335
336
337
    }

    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
338
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
339
340
341
342
    {
        return;
    }

343
    // Else : use base class interaction
344
345
346
347
    vtkBaseInteractorStyle::OnRightButtonUp();
}

void
348
VTKInteractorStyle::OnMouseWheelForward()
349
{
350
351
352
353
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onMouseWheelForwardFunction &&
       m_onMouseWheelForwardFunction(this))
354
    {
355
        return;
356
357
    }

358
    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
359
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
360
361
362
363
    {
        return;
    }

364
365
    // Else : use base class interaction
    vtkBaseInteractorStyle::OnMouseWheelForward();
366
367
368
}

void
369
VTKInteractorStyle::OnMouseWheelBackward()
370
{
371
372
373
374
    // Call custom function if exists, and return
    // if it returned `override=true`
    if(m_onMouseWheelBackwardFunction &&
       m_onMouseWheelBackwardFunction(this))
375
    {
376
        return;
377
378
    }

379
    // Default behavior : ignore mouse if simulation active
Nicholas Milef's avatar
Nicholas Milef committed
380
    if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG)
381
382
383
    {
        return;
    }
384
385
386

    // Else : use base class interaction
    vtkBaseInteractorStyle::OnMouseWheelBackward();
387
388
}
} // imstk