1 #ifndef SimTK_SIMBODY_VISUALIZER_H_
2 #define SimTK_SIMBODY_VISUALIZER_H_
3
4 /* -------------------------------------------------------------------------- *
5 * Simbody(tm) *
6 * -------------------------------------------------------------------------- *
7 * This is part of the SimTK biosimulation toolkit originating from *
8 * Simbios, the NIH National Center for Physics-Based Simulation of *
9 * Biological Structures at Stanford, funded under the NIH Roadmap for *
10 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
11 * *
12 * Portions copyright (c) 2010-14 Stanford University and the Authors. *
13 * Authors: Peter Eastman, Michael Sherman *
14 * Contributors: *
15 * *
16 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
17 * not use this file except in compliance with the License. You may obtain a *
18 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
19 * *
20 * Unless required by applicable law or agreed to in writing, software *
21 * distributed under the License is distributed on an "AS IS" BASIS, *
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
23 * See the License for the specific language governing permissions and *
24 * limitations under the License. *
25 * -------------------------------------------------------------------------- */
26
27 /** @file
28 Declares the Visualizer class used for collecting Simbody simulation results
29 for display and interaction through the visualizer. **/
30
31 #include "simbody/internal/common.h"
32
33 #include <utility> // for std::pair
34
35 namespace SimTK {
36
37 class MobilizedBody;
38 class MultibodySystem;
39 class DecorationGenerator;
40
41 /** Provide simple visualization of and interaction with a Simbody simulation,
42 with real time control of the frame rate.\ There are several operating modes
43 available, including real time operation permitting responsive user interaction
44 with the simulation.
45
46 Frames are sent to the renderer at a regular interval that is selectable, with
47 a default rate of 30 frames/second. The various operating modes provide
48 different methods of controlling which simulation frames are selected and how
49 they are synchronized for display.
50
51 <h3>Visualization modes</h3>
52
53 There are three operating modes for the Visualizer's display of simulation
54 results, selectable via setMode():
55
56 - <b>PassThrough</b>. This is the default mode. It sends through to the
57 renderer \e every frame that is received from the simulation, slowing down the
58 simulation if necessary so that the frames are presented at a selected frame
59 rate. But note that the simulation time will not be synchronized to real time;
60 because Simbody simulations generally proceed at a variable rate, the
61 regularly-spaced output frames will represent different amounts of simulated
62 time. If you want real time and simulation time synchronized, use the RealTime
63 mode.
64
65 - <b>Sampling</b>. This mode is useful for monitoring a simulation that is
66 allowed to run at full speed. We send frames for display at a maximum rate
67 given by the frame rate setting. After a frame is sent, all subsequent frames
68 received from the simulation are ignored until the frame interval has passed;
69 then the next received frame is displayed. This allows the simulation to
70 proceed at the fastest rate possible but time will be irregular and not all
71 frames generated by the simulation will be shown.
72
73 - <b>RealTime</b>. Synchronize frame times with the simulated time, slowing
74 down the simulation if it is running ahead of real time, as modifed by the
75 time scale; see setRealTimeScale(). Frames are sent to the renderer at the
76 selected frame rate. Smoothness is maintained by buffering up frames before
77 sending them; interactivity is maintained by keeping the buffer length below
78 human perception time (150-200ms). The presence and size of the buffer is
79 selectable; see setDesiredBufferLengthInSec().
80
81 <h3>User interaction</h3>
82
83 The Simbody visualizer provides some user interaction of its own, for
84 example allowing the user to control the viewpoint and display options. User
85 inputs that it does not interpret locally are passed on to the simulation,
86 and can be intercepted by registering InputListeners with the Visualizer. The
87 Visualizer provides a class Visualizer::InputSilo which is an InputListener
88 that simply captures and queues all user input, with the intent that a running
89 simulation will occasionally stop to poll the InputSilo to process any input
90 that has been collected.
91
92 <h3>Implementation notes</h3>
93
94 RealTime mode is worth some discussion. There is a simulation thread that
95 produces frames at a variable rate, and a draw thread that consumes frames at a
96 variable rate (by sending them to the renderer). We want to engineer things so
97 that frames are sent to the renderer at a steady rate that is synchronized with
98 simulation time (possibly after scaling). When a thread is running too fast,
99 that is easily handled by blocking the speeding thread for a while. The "too
100 slow" case takes careful handling.
101
102 In normal operation, we expect the simulation to take varying amounts of
103 real time to generate fixed amounts of simulation time, because we prefer
104 to use variable time-step integrators that control errors by taking smaller
105 steps in more difficult circumstances, and large steps through the easy
106 parts of the simulation. For real time operation, the simulation must of
107 course *average* real time performance; we use a frame buffer to smooth
108 out variable delivery times. That is, frames go into the buffer at an
109 irregular rate but are pulled off at a regular rate. A longer buffer can
110 mask wider deviations in frame time, at the expense of interactive response.
111 In most circumstances people cannot perceive delays below about 200ms, so
112 for good response the total delay should be kept around that level.
113
114 Despite the buffering, there will be occasions when the simulation can't
115 keep up with real time. A common cause of that is that a user has paused
116 either the simulation or the renderer, such as by hitting a breakpoint while
117 debugging. In that case we deem the proper behavior to be that when we
118 resume we should immediately resume real time behavior at a new start time,
119 \e not attempt to catch up to the previous real time by running at high speed.
120 As much as possible, we would like the simulation to behave just as it would
121 have without the interruption, but with a long pause where interrupted. We
122 deal with this situation by introducing a notion of "adjusted real time"
123 (AdjRT). That is a clock that tracks the real time interval counter, but uses
124 a variable base offset that is used to match it to the expected simulation
125 time. When the simulation is long delayed, we modify the AdjRT base when we
126 resume so that AdjRT once again matches the simulation time t. Adjustments
127 to the AdjRT base occur at the time we deliver frames to the renderer; at that
128 moment we compare the AdjRT reading to the frame's simulation time t and
129 correct AdjRT for future frames.
130
131 You can also run in RealTime mode without buffering. In that case frames are
132 sent directly from the simulation thread to the renderer, but the above logic
133 still applies. Simulation frames that arrive earlier than the corresponding
134 AdjRT are delayed; frames that arrive later are drawn immediately but cause
135 AdjRT to be readjusted to resynchronize. Overall performance can be better
136 in unbuffered RealTime mode because the States provided by the simulation do
137 not have to be copied before being drawn. However, intermittent slower-than-
138 realtime frame times cannot be smoothed over; they will cause rendering delays.
139
140 PassThrough and Sampling modes are much simpler because no synchronization
141 is done to the simulation times. There is only a single thread and draw
142 time scheduling works in real time without adjustment.
143
144 With the above explanation, you may be able to figure out most of what comes
145 out of the dumpStats() method which can be used to help diagnose performance
146 problems. **/
147 class SimTK_SIMBODY_EXPORT Visualizer {
148 public:
149 class FrameController; // defined below
150 class BodyFollower; // declared below, defined in Visualizer.cpp
151 class InputListener; // defined in Visualizer_InputListener.h
152 class InputSilo; // "
153 class Reporter; // defined in Visualizer_Reporter.h
154
155
156 /** Construct a new %Visualizer for the indicated System, and launch the
157 visualizer display executable from a default or specified location. The camera's
158 "up" direction will initially be set to match the "up" direction hint that is
159 stored with the supplied \a system; the default is that "up" is in the
160 direction of the positive Y axis. The background will normally include a
161 ground plane and sky, but if the \a system has been set to request a uniform
162 background we'll use a plain white background instead. You can override the
163 chosen defaults using %Visualizer methods setSystemUpDirection() and
164 setBackgroundType().
165
166 Simbody is shipped with a separate executable program simbody-visualizer
167 (simbody-visualizer_d if building as Debug) that provides the graphics display
168 and collects user input. Normally that executable is installed in the "bin"
169 subdirectory of the Simbody installation directory. However, first we look in
170 the same directory as the currently-running executable and, if found, we will
171 use that visualizer. If no visualizer is found with the executable, we check if
172 environment variables SIMBODY_HOME or SimTK_INSTALL_DIR exist, and look in
173 their "bin" (or "libexec/simbody" on UNIX) subdirectories if so. Next, we
174 attempt to use the relative path from the SimTKsimbody library to the
175 simbody-visualizer (this helps if Simbody is relocated, but does not work on
176 Windows, or if using static Simbody libraries). Then, we check the installed
177 location of the visualizer, as specified when Simbody is compiled. If the
178 visualizer is not there, we'll look in platform-specific default locations.
179 The other constructor allows specification of a search path that will be
180 checked before attempting to find the installation directory.
181
182 If you want to override the name of the visualizer executable for which Simbody
183 searches, set the environment variable SIMBODY_VISUALIZER_NAME
184 to the desired executable name. For example, if you want to use the
185 debug visualizer with release libraries, set SIMBODY_VISUALIZER_NAME
186 to simbody-visualizer_d.
187
188 The SimTK::Pathname class is used to process the supplied search path, which
189 can consist of absolute, working directory-relative, or executable
190 directory-relative path names.
191
192 @see SimTK::Pathname **/
193 explicit Visualizer(const MultibodySystem& system);
194
195 /** Construct a new Visualizer for a given system, with a specified search
196 path for locating the SimbodyVisualizer executable. The search path is
197 checked \e after looking in the current executable directory, and \e before
198 trying to locate the Simbody or SimTK installation directory. See the other
199 constructor's documentation for more information. **/
200 Visualizer(const MultibodySystem& system,
201 const Array_<String>& searchPath);
202
203 /** Copy constructor has reference counted, shallow copy semantics;
204 that is, the Visualizer copy is just another reference to the same
205 Visualizer object. **/
206 Visualizer(const Visualizer& src);
207 /** Copy assignment has reference counted, shallow copy semantics;
208 that is, the Visualizer copy is just another reference to the same
209 Visualizer object. **/
210 Visualizer& operator=(const Visualizer& src);
211 /** InputListener, FrameController, and DecorationGenerator objects are
212 destroyed here when the last reference is deleted. **/
213 ~Visualizer();
214
215 /** Ask the visualizer to shut itself down immediately. This will cause the
216 display window to close and the associated process to die. This method returns
217 immediately but it may be some time later when the visualizer acts on the
218 instruction; there is no way to wait for it to die. Normally the visualizer
219 will persist even after the death of the simulator connection unless you have
220 called setShutdownWhenDestructed() to make shutdown() get called automatically.
221 @see setShutdownWhenDestructed() **/
222 void shutdown();
223
224 /** Set the flag that determines whether we will automatically send a Shutdown
225 message to the visualizer when this %Visualizer object is destructed.
226 Normally we allow the GUI to persist even after death of the simulator
227 connection, unless an explicit call to shutdown() is made.
228 @see getShutdownWhenDestructed(), shutdown() **/
229 Visualizer& setShutdownWhenDestructed(bool shouldShutdown);
230
231 /** Return the current setting of the "shutdown when destructed" flag. By
232 default this is false.
233 @see setShutdownWhenDestructed(), shutdown() **/
234 bool getShutdownWhenDestructed() const;
235
236 /** These are the operating modes for the Visualizer, with PassThrough the
237 default mode. See the documentation for the Visualizer class for more
238 information about the modes. **/
239 enum Mode {
240 /** Send through to the renderer every frame that is received from the
241 simulator (default mode). **/
242 PassThrough = 1,
243 /** Sample the results from the simulation at fixed real time intervals
244 given by the frame rate. **/
245 Sampling = 2,
246 /** Synchronize real frame display times with the simulated time. **/
247 RealTime = 3
248 };
249
250 /** These are the types of backgrounds the visualizer currently supports.
251 You can choose what type to use programmatically, and users can override that
252 choice in the GUI. Each of these types may use additional data (such as the
253 background color) when the type is selected. **/
254 enum BackgroundType {
255 /** Show a ground plane on which shadows may be cast, as well as a sky
256 in the far background. **/
257 GroundAndSky = 1,
258 /** Display a solid background color that has been provided elsewhere. **/
259 SolidColor = 2
260 };
261
262 /** The visualizer may predefine some menus; if you need to refer to one
263 of those use its menu Id as defined here. Note that the id numbers here
264 are negative numbers, which are not allowed for user-defined menu ids. **/
265 enum PredefinedMenuIds {
266 /** The id of the predefined View pull-down. **/
267 ViewMenuId = -1
268 };
269
270 /** @name visualizer display options
271 These methods provide programmatic control over some of the visualizer's
272 display options. Typically these can be overridden by the user directly in
273 the GUI, but these are useful for setting sensible defaults. In particular,
274 the Ground and Sky background, which is the GUI default, is not appropriate
275 for some systems (molecules for example). **/
276 /**@{**/
277
278
279 /** Change the background mode currently in effect in the GUI.\ By default
280 we take the desired background type from the System, which will usually be
281 at its default value which is to show a ground plane and sky. You can override
282 that default choice with this method.
283 @param background The background type to use.
284 @return A reference to this Visualizer so that you can chain "set" calls.
285 @note Molmodel's CompoundSystem requests a solid background by default, since
286 ground and sky is not the best way to display a molecule! **/
287 Visualizer& setBackgroundType(BackgroundType background);
288
289
290 /** Set the background color.\ This will be used when the solid background
291 mode is in effect but has no effect otherwise. This is a const method so you
292 can call it from within a FrameController, for example if you want to flash
293 the background color.
294 @param color The background color in r,g,b format with [0,1] range.
295 @return A const reference to this Visualizer so that you can chain "set"
296 calls, provided subsequent ones are also const. **/
297 const Visualizer& setBackgroundColor(const Vec3& color) const;
298
299 /** Control whether shadows are generated when the GroundAndSky background
300 type is in effect.\ This has no effect if the ground plane is not being
301 displayed. The default if for shadows to be displayed. This is a const method
302 so you can call it from within a FrameController.
303 @param showShadows Set true to have shadows generated; false for none.
304 @see setBackgroundType()
305 @return A const reference to this Visualizer so that you can chain "set"
306 calls, provided subsequent ones are also const. **/
307 const Visualizer& setShowShadows(bool showShadows) const;
308
309 /** Control whether frame rate is shown in the Visualizer.\ This is a const
310 method so you can call it from within a FrameController.
311 @param showFrameRate Set true to show the frame rate; false for none.
312 @return A const reference to this Visualizer so that you can chain "set"
313 calls, provided subsequent ones are also const. **/
314 const Visualizer& setShowFrameRate(bool showFrameRate) const;
315
316 /** Control whether simulation time is shown in the Visualizer.\ This is a const
317 method so you can call it from within a FrameController.
318 @param showSimTime Set true to show the simulation time; false for none.
319 @return A const reference to this Visualizer so that you can chain "set"
320 calls, provided subsequent ones are also const. **/
321 const Visualizer& setShowSimTime(bool showSimTime) const;
322
323 /** Control whether frame number is shown in the Visualizer.\ This is a const
324 method so you can call it from within a FrameController.
325 @param showFrameNumber Set true to show the frame number; false for none.
326 @return A const reference to this Visualizer so that you can chain "set"
327 calls, provided subsequent ones are also const. **/
328 const Visualizer& setShowFrameNumber(bool showFrameNumber) const;
329
330 /** Change the title on the main visualizer window.\ The default title
331 is Simbody \e version : \e exename, where \e version is the current Simbody
332 version number in major.minor.patch format and \e exename is the name of the
333 executing simulation application's executable file (without suffix if any).
334 @param[in] title
335 The new window title. The amount of room for the title varies; keep
336 it short.
337 @return A const reference to this Visualizer so that you can chain "set"
338 calls, provided subsequent ones are also const.
339 @see SimTK_version_simbody(), Pathname::getThisExecutablePath(),
340 Pathname::desconstructPathname() **/
341 const Visualizer& setWindowTitle(const String& title) const;
342 /**@}**/
343
344 /** @name Visualizer options
345 These methods are used for setting a variety of options for the Visualizer's
346 behavior, normally prior to sending it the first frame. **/
347 /**@{**/
348
349 /** Set the coordinate direction that should be considered the System's "up"
350 direction.\ When the ground and sky background is in use, this is the
351 direction that serves as the ground plane normal, and is used as the initial
352 orientation for the camera's up direction (which is subsequently under user
353 or program control and can point anywhere). If you don't set this explicitly
354 here, the Visualizer takes the default up direction from the System, which
355 provides a method allowing the System's creator to specify it, with the +Y
356 axis being the default.
357 @param[in] upDirection
358 This must be one of the CoordinateAxis constants XAxis, YAxis, or ZAxis,
359 or one of the opposite directions -XAxis, -YAxis, or -ZAxis.
360 @return A writable reference to this Visualizer so that you can chain "set"
361 calls in the manner of chained assignments. **/
362 Visualizer& setSystemUpDirection(const CoordinateDirection& upDirection);
363 /** Get the value the Visualizer is using as the System "up" direction (
364 not to be confused with the camera "up" direction). **/
365 CoordinateDirection getSystemUpDirection() const;
366
367 /** Set the height at which the ground plane should be displayed when the
368 GroundAndSky background type is in effect.\ This is interpreted along the
369 system "up" direction that was specified in the Visualizer's System or was
370 overridden with the setSystemUpDirection() method. The default value is zero,
371 meaning that the ground plane passes through the ground origin.
372 @param height
373 The position of the ground plane along the system "up" direction that
374 serves as the ground plane normal. Note that \a height is \e along the
375 up direction, meaning that if up is one of the negative coordinate axis
376 directions a positive \a height will move the ground plane to a more
377 negative position.
378 @return A reference to this Visualizer so that you can chain "set" calls.
379 @see setSystemUpDirection(), setBackgroundType() **/
380 Visualizer& setGroundHeight(Real height);
381 /** Get the value the Visualizer considers to be the height of the ground
382 plane for this System.\ The value must be interpreted along the System's "up"
383 direction. @see setSystemUpDirection() **/
384 Real getGroundHeight() const;
385
386
387 /** Set the operating mode for the Visualizer. See \ref Visualizer::Mode for
388 choices, and the discussion for the Visualizer class for meanings.
389 @param[in] mode The new Mode to use.
390 @return A reference to this Visualizer so that you can chain "set" calls. **/
391 Visualizer& setMode(Mode mode);
392 /** Get the current mode being used by the Visualizer. See \ref Visualizer::Mode
393 for the choices, and the discussion for the Visualizer class for meanings. **/
394 Mode getMode() const;
395
396 /** Set the frame rate in frames/sec (of real time) that you want the
397 Visualizer to attempt to achieve. This affects all modes. The default is 30
398 frames per second. Set the frame rate to zero to return to the default
399 behavior.
400 @param[in] framesPerSec
401 The desired frame rate; specify as zero to get the default.
402 @return A reference to this Visualizer so that you can chain "set" calls.
403 **/
404 Visualizer& setDesiredFrameRate(Real framesPerSec);
405 /** Get the current value of the frame rate the Visualizer has been asked to
406 attempt; this is not necessarily the rate actually achieved. A return value of
407 zero means the Visualizer is using its default frame rate, which may be
408 dependent on the current operating mode.
409 @see setDesiredFrameRate() for more information. **/
410 Real getDesiredFrameRate() const;
411
412 /** In RealTime mode we normally assume that one unit of simulated time should
413 map to one second of real time; however, in some cases the time units are not
414 seconds, and in others you may want to run at some multiple or fraction of
415 real time. Here you can say how much simulated time should equal one second of
416 real time. For example, if your simulation runs in seconds, but you want to
417 run twice as fast as real time, then call setRealTimeScale(2.0), meaning that
418 two simulated seconds will pass for every one real second. This call will have
419 no immediate effect if you are not in RealTime mode, but the value will be
420 remembered.
421
422 @param[in] simTimePerRealSecond
423 The number of units of simulation time that should be displayed in one second
424 of real time. Zero or negative value will be interpeted as the default ratio
425 of 1:1.
426 @return A reference to this Visualizer so that you can chain "set" calls.
427 **/
428 Visualizer& setRealTimeScale(Real simTimePerRealSecond);
429 /** Return the current time scale, which will be 1 by default.
430 @see setRealTimeScale() for more information. **/
431 Real getRealTimeScale() const;
432
433 /** When running an interactive realtime simulation, you can smooth out changes
434 in simulation run rate by buffering frames before sending them on for
435 rendering. The length of the buffer introduces an intentional response time
436 lag from when a user reacts to when he can see a response from the simulator.
437 Under most circumstances a lag of 150-200ms is undetectable. The default
438 buffer length is the time represented by the number of whole frames
439 that comes closest to 150ms; 9 frames at 60fps, 5 at 30fps, 4 at 24fps, etc.
440 To avoid frequent block/unblocking of the simulation thread, the buffer is
441 not kept completely full; you can use dumpStats() if you want to see how the
442 buffer was used during a simulation. Shorten the buffer to improve
443 responsiveness at the possible expense of smoothness. Note that the total lag
444 time includes not only the buffer length here, but also lag induced by the
445 time stepper taking steps that are larger than the frame times. For maximum
446 responsiveness you should keep the integrator step sizes limited to about
447 100ms, or reduce the buffer length so that worst-case lag doesn't go much over
448 200ms.
449 @param[in] bufferLengthInSec
450 This is the target time length for the buffer. The actual length is the nearest
451 integer number of frames whose frame times add up closest to the request. If
452 you ask for a non-zero value, you will always get at least one frame in the
453 buffer. If you ask for zero, you'll get no buffering at all. To restore the
454 buffer length to its default value, pass in a negative number.
455 @return A reference to this Visualizer so that you can chain "set" calls. **/
456 Visualizer& setDesiredBufferLengthInSec(Real bufferLengthInSec);
457 /** Get the current value of the desired buffer time length the Visualizer
458 has been asked to use for smoothing the frame rate, or the default value
459 if none has been requested. The actual value will differ from this number
460 because the buffer must contain an integer number of frames.
461 @see getActualBufferTime() to see the frame-rounded buffer length **/
462 Real getDesiredBufferLengthInSec() const;
463 /** Get the actual length of the real time frame buffer in seconds, which
464 may differ from the requested time because the buffer contains an integer
465 number of frames. **/
466 Real getActualBufferLengthInSec() const;
467 /** Get the actual length of the real time frame buffer in number of frames. **/
468 int getActualBufferLengthInFrames() const;
469
470 /** Add a new input listener to this Visualizer, methods of which will be
471 called when the GUI detects user-driven events like key presses, menu picks,
472 and slider or mouse moves. See Visualizer::InputListener for more
473 information. The Visualizer takes over ownership of the supplied \a listener
474 object and deletes it upon destruction of the Visualizer; don't delete it
475 yourself.
476 @return An integer index you can use to find this input listener again. **/
477 int addInputListener(InputListener* listener);
478 /** Return the count of input listeners added with addInputListener(). **/
479 int getNumInputListeners() const;
480 /** Return a const reference to the i'th input listener. **/
481 const InputListener& getInputListener(int i) const;
482 /** Return a writable reference to the i'th input listener. **/
483 InputListener& updInputListener(int i);
484
485 /** Add a new frame controller to this Visualizer, methods of which will be
486 called just prior to rendering a frame for the purpose of simulation-controlled
487 camera positioning and other frame-specific effects.
488 See Visualizer::FrameController for more information. The Visualizer takes
489 over ownership of the supplied \a controller object and deletes it upon
490 destruction of the Visualizer; don't delete it yourself.
491 @return An integer index you can use to find this frame controller again. **/
492 int addFrameController(FrameController* controller);
493 /** Return the count of frame controllers added with addFrameController(). **/
494 int getNumFrameControllers() const;
495 /** Return a const reference to the i'th frame controller. **/
496 const FrameController& getFrameController(int i) const;
497 /** Return a writable reference to the i'th frame controller. **/
498 FrameController& updFrameController(int i);
499
500 /**@}**/
501
502
503 /** @name Frame drawing methods
504 These are used to report simulation frames to the Visualizer. Typically
505 the report() method will be called from a Reporter invoked by a TimeStepper,
506 but it can also be useful to invoke directly to show preliminary steps in a
507 simulation, to replay saved States later, and to display frames when using
508 an Integrator directly rather than through a TimeStepper.
509
510 How frames are handled after they have been reported depends on the specific
511 method called, and on the Visualizer's current Mode. **/
512
513 /**@{**/
514 /** Report that a new simulation frame is available for rendering. Depending
515 on the current Visualizer::Mode, handling of the frame will vary:
516
517 @par PassThrough
518 All frames will be rendered, but the calling thread (that is, the simulation)
519 may be blocked if the next frame time has not yet been reached or if the
520 renderer is unable to keep up with the rate at which frames are being supplied
521 by the simulation.
522
523 @par Sampling
524 The frame will be rendered immediately if the next sample time has been reached
525 or passed, otherwise the frame will be ignored and report() will return
526 immediately.
527
528 @par RealTime
529 Frames are queued to smooth out the time stepper's variable time steps. The
530 calling thread may be blocked if the buffer is full, or if the simulation time
531 is too far ahead of real time. Frames will be dropped if they come too
532 frequently; only the ones whose simulated times are at or near a frame time
533 will be rendered. Frames that come too late will be queued for rendering as
534 soon as possible, and also reset the expected times for subsequent frames so
535 that real time operation is restored. **/
536 void report(const State& state) const;
537
538 /** In RealTime mode there will typically be frames still in the buffer at
539 the end of a simulation.\ This allows you to wait while the buffer empties.
540 When this returns, all frames that had been supplied via report() will have
541 been sent to the renderer and the buffer will be empty. Returns immediately
542 if not in RealTime mode, if there is no buffer, or if the buffer is already
543 empty. **/
544 void flushFrames() const;
545
546 /** This method draws a frame unconditionally without queuing or checking
547 the frame rate. Typically you should use the report() method instead, and
548 let the the internal queuing and timing system decide when to call
549 drawFrameNow(). **/
550 void drawFrameNow(const State& state) const;
551 /**@}**/
552
553
554 /** @name Scene-building methods
555 These methods are used to add permanent elements to the scene being displayed
556 by the Visualizer. Once added, these elements will contribute to every frame.
557 Calling one of these methods requires writable (non-const) access to the
558 Visualizer object; you can't call them from within a FrameController object.
559 Note that adding DecorationGenerators does allow different
560 geometry to be produced for each frame; however, once added a
561 DecorationGenerator will be called for \e every frame generated. **/
562 /**@{**/
563
564 /** Add a new pull-down menu to the visualizer's display. A label
565 for the pull-down button is provided along with an integer identifying the
566 particular menu. A list of (string,int) pairs defines the menu and submenu
567 item labels and associated item numbers. The item numbers must be unique
568 across the entire menu and all its submenus. The strings have a pathname-like
569 syntax, like "submenu/item1", "submenu/item2", "submenu/lowermenu/item1", etc.
570 that is used to define the pulldown menu layout.
571 @param title the title to display on the menu's pulldown button
572 @param id an integer value >= 0 that uniquely identifies this menu
573 @param items item names, possibly with submenus as specified above, with
574 associated item numbers
575 When a user picks an item on a menu displayed in the visualizer, that
576 selection is delievered to the simulation application via an InputListener
577 associated with this Visualizer. The selection will be identified by
578 (\a id, itemNumber) pair.
579 @return A reference to this Visualizer so that you can chain "add" and
580 "set" calls. **/
581 Visualizer& addMenu(const String& title, int id,
582 const Array_<std::pair<String, int> >& items);
583
584 /** Add a new slider to the visualizer's display.
585 @param title the title to display next to the slider
586 @param id an integer value that uniquely identifies this slider
587 @param min the minimum value the slider can have
588 @param max the maximum value the slider can have
589 @param value the initial value of the slider, which must be between
590 min and max
591 When a user moves a slider displayed in the visualizer, the new value
592 is delievered to the simulation application via an InputListener associated
593 with this Visualizer. The slider will be identified by the \a id supplied
594 here.
595 @return A reference to this Visualizer so that you can chain "add" and
596 "set" calls. **/
597 Visualizer& addSlider(const String& title, int id, Real min, Real max, Real value);
598
599 /** Add an always-present, body-fixed piece of geometry like the one passed in,
600 but attached to the indicated body. The supplied transform is applied on top of
601 whatever transform is already contained in the supplied geometry, and any body
602 index stored with the geometry is ignored.
603 @return An integer index you can use to find this decoration again. **/
604 int addDecoration(MobilizedBodyIndex mobodIx, const Transform& X_BD,
605 const DecorativeGeometry& geometry);
606 /** Return the count of decorations added with addDecoration(). **/
607 int getNumDecorations() const;
608 /** Return a const reference to the i'th decoration. **/
609 const DecorativeGeometry& getDecoration(int i) const;
610 /** Return a writable reference to the i'th decoration. This is allowed for
611 a const %Visualizer since it is just a decoration. **/
612 DecorativeGeometry& updDecoration(int i) const;
613
614 /** Add an always-present rubber band line, modeled after the DecorativeLine
615 supplied here. The end points of the supplied line are ignored, however: at
616 run time the spatial locations of the two supplied stations are calculated and
617 used as end points.
618 @return An integer index you can use to find this rubber band line again. **/
619 int addRubberBandLine(MobilizedBodyIndex b1, const Vec3& station1,
620 MobilizedBodyIndex b2, const Vec3& station2,
621 const DecorativeLine& line);
622 /** Return the count of rubber band lines added with addRubberBandLine(). **/
623 int getNumRubberBandLines() const;
624 /** Return a const reference to the i'th rubber band line. **/
625 const DecorativeLine& getRubberBandLine(int i) const;
626 /** Return a writable reference to the i'th rubber band line. This is allowed
627 for a const %Visualizer since it is just a decoration. **/
628 DecorativeLine& updRubberBandLine(int i) const;
629
630 /** Add a DecorationGenerator that will be invoked to add dynamically generated
631 geometry to each frame of the the scene. The Visualizer assumes ownership of the
632 object passed to this method, and will delete it when the Visualizer is
633 deleted.
634 @return An integer index you can use to find this decoration generator
635 again. **/
636 int addDecorationGenerator(DecorationGenerator* generator);
637 /** Return the count of decoration generators added with
638 addDecorationGenerator(). **/
639 int getNumDecorationGenerators() const;
640 /** Return a const reference to the i'th decoration generator. **/
641 const DecorationGenerator& getDecorationGenerator(int i) const;
642 /** Return a writable reference to the i'th decoration generator. **/
643 DecorationGenerator& updDecorationGenerator(int i);
644 /**@}**/
645
646 /** @name Frame control methods
647 These methods can be called prior to rendering a frame to control how the
648 camera is positioned for that frame. These can be invoked from within a
649 FrameController object for runtime camera control and other effects. See the
650 Visualizer::BodyFollower class for an example of a FrameController that causes
651 the camera to follow a body. **/
652 /**@{**/
653
654 /** Set the transform defining the position and orientation of the camera.
655
656 @param[in] X_GC This is the transform giving the pose of the camera's
657 frame C in the ground frame G; see below for a precise
658 description.
659
660 Our camera uses a right-handed frame with origin at the image location,
661 with axes oriented as follows: the x axis is to the right, the y axis is the
662 "up" direction, and the z axis is the "back" direction; that is, the camera is
663 looking in the -z direction. If your simulation coordinate system is different,
664 such as the common "virtual world" system where ground is the x-y plane
665 (x right and y "in") and z is up, be careful to account for that when
666 positioning the camera.
667
668 For example, in the virtual world coordinate system, setting \a X_GC to
669 identity would put the camera at the ground origin with the x axis as expected,
670 but the camera would be looking down (your -z) with the camera's "up" direction
671 aligned with your y. In this case to make the camera look in the y direction
672 with up in z, you would need to rotate it +90 degrees about the x axis:
673 @code
674 Visualizer viz;
675 // ...
676
677 // Point camera along Ground's y axis with z up, by rotating the camera
678 // frame's z axis to align with Ground's -y.
679 viz.setCameraTransform(Rotation(Pi/2, XAxis));
680 @endcode **/
681 const Visualizer& setCameraTransform(const Transform& X_GC) const;
682
683 /** Move the camera forward or backward so that all geometry in the scene is
684 visible. **/
685 const Visualizer& zoomCameraToShowAllGeometry() const;
686
687 /** Rotate the camera so that it looks at a specified point.
688 @param point the point to look at
689 @param upDirection a direction which should point upward as seen by the camera
690 **/
691 const Visualizer& pointCameraAt(const Vec3& point, const Vec3& upDirection) const;
692
693 /** Set the camera's vertical field of view, measured in radians. **/
694 const Visualizer& setCameraFieldOfView(Real fov) const;
695
696 /** Set the distance from the camera to the near and far clipping planes. **/
697 const Visualizer& setCameraClippingPlanes(Real nearPlane, Real farPlane) const;
698
699 /** Change the value currently shown on one of the sliders.
700 @param slider the id given to the slider when created
701 @param value a new value for the slider; if out of range it will
702 be at one of the extremes **/
703 const Visualizer& setSliderValue(int slider, Real value) const;
704
705 /** Change the allowed range for one of the sliders.
706 @param slider the id given to the slider when created
707 @param newMin the new lower limit on the slider range, <= newMax
708 @param newMax the new upper limit on the slider range, >= newMin
709 The slider's current value remains unchanged if it still fits in the
710 new range, otherwise it is moved to the nearest limit. **/
711 const Visualizer& setSliderRange(int slider, Real newMin, Real newMax) const;
712
713
714 /**@}**/
715
716 /** @name Methods for debugging and statistics **/
717 /**@{**/
718 /** Dump statistics to the given ostream (for example, std::cout). **/
719 void dumpStats(std::ostream& o) const;
720 /** Reset all statistics to zero. **/
721 void clearStats();
722 /**@}**/
723
724 /** @name Internal use only **/
725 /**@{**/
726 const Array_<InputListener*>& getInputListeners() const;
727 const Array_<FrameController*>& getFrameControllers() const;
728 const MultibodySystem& getSystem() const;
729 int getRefCount() const;
730 /**@}**/
731
732 class Impl;
733 //--------------------------------------------------------------------------
734 private:
735 explicit Visualizer(Impl* impl);
736 Impl* impl;
737
getImpl()738 const Impl& getImpl() const {assert(impl); return *impl;}
updImpl()739 Impl& updImpl() {assert(impl); return *impl;}
740 friend class Impl;
741 };
742
743 /** This abstract class represents an object that will be invoked by the
744 Visualizer just prior to rendering each frame. You can use this to call any
745 of the const (runtime) methods of the Visualizer, typically to control the
746 camera, and you can also add some geometry to the scene, print messages to
747 the console, and so on. **/
748 class SimTK_SIMBODY_EXPORT Visualizer::FrameController {
749 public:
750 /** The Visualizer is just about to generate and render a frame
751 corresponding to the given State.
752 @param[in] viz
753 The Visualizer that is doing the rendering.
754 @param[in] state
755 The State that is being used to generate the frame about to be
756 rendered by \a viz.
757 @param[in,out] geometry
758 DecorativeGeometry being accumulated for rendering in this frame;
759 be sure to \e append if you have anything to add.
760 **/
761 virtual void generateControls(const Visualizer& viz,
762 const State& state,
763 Array_<DecorativeGeometry>& geometry) = 0;
764
765 /** Destructor is virtual; be sure to override it if you have something
766 to clean up at the end. **/
~FrameController()767 virtual ~FrameController() {}
768 };
769
770 /** Causes the camera to point at and follow a point fixed on a body (a
771 station). This might be useful if your system translates substantially
772 and would thus leave the field of view of a stationary camera. **/
773 // This class is based on the BodyWatcher class that used to be in TimsBox.cpp.
774 class SimTK_SIMBODY_EXPORT Visualizer::BodyFollower :
775 public Visualizer::FrameController {
776 public:
777 /**
778 @param[in] mobodB
779 The MobilizedBody to follow, designated as B.
780 @param[in] stationPinB
781 The location of the station P on the body to follow, expressed in B. By
782 default, P is the origin of the MobilizedBody.
783 @param[in] offset
784 Position of the camera from P, expressed in ground. Cannot be the zero
785 vector. By default, this is (1, 1, 1) + h * u, where h is
786 Visualizer::getGroundHeight() and u is
787 Visualizer::getSystemUpDirection().
788 @param[in] upDirection
789 Controls the rotation of the camera about the offset vector. The
790 camera's up (+y) direction will be aligned with this vector as best as
791 is possible. Expressed in ground. By default, this is
792 Visualizer::getSystemUpDirection(); it's unlikely that you want
793 something other than the default.
794 **/
795 BodyFollower(const MobilizedBody& mobodB,
796 const Vec3& stationPinB = Vec3(0, 0, 0),
797 const Vec3& offset = Vec3(NaN),
798 const UnitVec3& upDirection = UnitVec3());
799
800 void generateControls(
801 const Visualizer& viz,
802 const State& state,
803 Array_< DecorativeGeometry >& geometry) override;
804
805 private:
806 const MobilizedBody& m_mobodB;
807 const Vec3& m_stationPinB;
808 const Vec3& m_offset;
809 const UnitVec3& m_upDirection;
810 };
811
812 /** OBSOLETE: This provides limited backwards compatibility with the old
813 VTK Visualizer that is no longer supported.\ Switch to Visualizer instead. **/
814 typedef Visualizer VTKVisualizer;
815
816 } // namespace SimTK
817
818 #endif // SimTK_SIMBODY_VISUALIZER_H_
819