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