• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <optional>
19 
20 #include "media/Pose.h"
21 
22 namespace android {
23 namespace media {
24 
25 /**
26  * Limits a stream of poses to a given maximum translational and rotational velocities.
27  *
28  * Normal operation:
29  *
30  * Pose3f output;
31  * PoseRateLimiter limiter(...);
32  *
33  * // Limiting is disabled. Output will be the same as last input.
34  * limiter.setTarget(...);
35  * output = limiter.calculatePose(...);
36  * limiter.setTarget(...);
37  * output = limiter.calculatePose(...);
38  *
39  * // Enable limiting. Output will no longer be necessarily the same as last input.
40  * limiter.enable();
41  * limiter.setTarget(...);
42  * output = limiter.calculatePose(...);
43  * limiter.setTarget(...);
44  * output = limiter.calculatePose(...);
45  *
46  * // When eventually the output has been able to catch up with the last input, the limited will be
47  * // automatically disabled again and the output will match the input again.
48  * limiter.setTarget(...);
49  * output = limiter.calculatePose(...);
50  *
51  * As shown above, the limiter is turned on manually via enable(), but turns off automatically as
52  * soon as the output is able to catch up to the input. The intention is that rate limiting will be
53  * turned on at specific times to smooth out any artificial discontinuities introduced to the pose
54  * stream, but the rest of the time will be a simple passthrough.
55 
56  * setTarget(...) and calculatePose(...) don't have to be ordered in any particular way. However,
57  * setTarget or reset() must be called at least once prior to the first calculatePose().
58  *
59  * Calling reset() instead of setTarget() forces the output to the given pose and disables rate
60  * limiting.
61  *
62  * This implementation is thread-compatible, but not thread-safe.
63  */
64 class PoseRateLimiter {
65   public:
66     struct Options {
67         float maxTranslationalVelocity = std::numeric_limits<float>::infinity();
68         float maxRotationalVelocity = std::numeric_limits<float>::infinity();
69     };
70 
71     explicit PoseRateLimiter(const Options& options);
72 
73     void enable();
74 
75     void reset(const Pose3f& target);
76     void setTarget(const Pose3f& target);
77 
78     Pose3f calculatePose(int64_t timestamp);
79 
80     std::string toString(unsigned level) const;
81 
82   private:
83     struct Point {
84         Pose3f pose;
85         int64_t timestamp;
86     };
87 
88     const Options mOptions;
89     bool mLimiting;
90     std::optional<Pose3f> mTargetPose;
91     std::optional<Point> mOutput;
92 };
93 
94 }  // namespace media
95 }  // namespace android
96