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 
17 #include "ModeSelector.h"
18 
19 #include <gtest/gtest.h>
20 
21 #include "media/QuaternionUtil.h"
22 #include "TestUtil.h"
23 
24 namespace android {
25 namespace media {
26 namespace {
27 
28 using Eigen::Quaternionf;
29 using Eigen::Vector3f;
30 
TEST(ModeSelector,Initial)31 TEST(ModeSelector, Initial) {
32     ModeSelector::Options options;
33     ModeSelector selector(options);
34 
35     selector.calculate(0);
36     EXPECT_EQ(HeadTrackingMode::STATIC, selector.getActualMode());
37     EXPECT_EQ(selector.getHeadToStagePose(), Pose3f());
38 }
39 
TEST(ModeSelector,InitialWorldRelative)40 TEST(ModeSelector, InitialWorldRelative) {
41     const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
42 
43     ModeSelector::Options options;
44     ModeSelector selector(options, HeadTrackingMode::WORLD_RELATIVE);
45 
46     selector.setWorldToHeadPose(0, worldToHead);
47     selector.setScreenStable(0, true);
48     selector.calculate(0);
49     EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
50     EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse());
51 }
52 
TEST(ModeSelector,InitialScreenRelative)53 TEST(ModeSelector, InitialScreenRelative) {
54     const Pose3f screenToHead({1, 2, 3}, Quaternionf::UnitRandom());
55 
56     ModeSelector::Options options;
57     ModeSelector selector(options, HeadTrackingMode::SCREEN_RELATIVE);
58 
59     selector.setScreenToHeadPose(0, screenToHead);
60     selector.calculate(0);
61     EXPECT_EQ(HeadTrackingMode::SCREEN_RELATIVE, selector.getActualMode());
62     EXPECT_EQ(selector.getHeadToStagePose(), screenToHead.inverse());
63 }
64 
TEST(ModeSelector,WorldRelative)65 TEST(ModeSelector, WorldRelative) {
66     const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
67     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
68 
69     ModeSelector::Options options;
70     ModeSelector selector(options);
71 
72     selector.setScreenToStagePose(screenToStage);
73     selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
74     selector.setWorldToHeadPose(0, worldToHead);
75     selector.setScreenStable(0, true);
76     selector.calculate(0);
77     EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
78     EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse() * screenToStage);
79 }
80 
TEST(ModeSelector,WorldRelativeUnstable)81 TEST(ModeSelector, WorldRelativeUnstable) {
82     const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
83     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
84 
85     ModeSelector::Options options{.freshnessTimeout = 100};
86     ModeSelector selector(options);
87 
88     selector.setScreenToStagePose(screenToStage);
89     selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
90     selector.setWorldToHeadPose(0, worldToHead);
91     selector.setScreenStable(0, false);
92     selector.calculate(10);
93     EXPECT_EQ(HeadTrackingMode::STATIC, selector.getActualMode());
94     EXPECT_EQ(selector.getHeadToStagePose(), screenToStage);
95 }
96 
TEST(ModeSelector,WorldRelativeStableStale)97 TEST(ModeSelector, WorldRelativeStableStale) {
98     const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
99     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
100 
101     ModeSelector::Options options{.freshnessTimeout = 100};
102     ModeSelector selector(options);
103 
104     selector.setScreenToStagePose(screenToStage);
105     selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
106     selector.setWorldToHeadPose(100, worldToHead);
107     selector.setScreenStable(0, true);
108     selector.calculate(101);
109     EXPECT_EQ(HeadTrackingMode::STATIC, selector.getActualMode());
110     EXPECT_EQ(selector.getHeadToStagePose(), screenToStage);
111 }
112 
TEST(ModeSelector,WorldRelativeStale)113 TEST(ModeSelector, WorldRelativeStale) {
114     const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
115     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
116 
117     ModeSelector::Options options{.freshnessTimeout = 100};
118     ModeSelector selector(options);
119 
120     selector.setScreenToStagePose(screenToStage);
121     selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
122     selector.setWorldToHeadPose(0, worldToHead);
123     selector.calculate(101);
124     EXPECT_EQ(HeadTrackingMode::STATIC, selector.getActualMode());
125     EXPECT_EQ(selector.getHeadToStagePose(), screenToStage);
126 }
127 
TEST(ModeSelector,ScreenRelative)128 TEST(ModeSelector, ScreenRelative) {
129     const Pose3f screenToHead({1, 2, 3}, Quaternionf::UnitRandom());
130     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
131 
132     ModeSelector::Options options;
133     ModeSelector selector(options);
134 
135     selector.setScreenToStagePose(screenToStage);
136     selector.setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
137     selector.setScreenToHeadPose(0, screenToHead);
138     selector.calculate(0);
139     EXPECT_EQ(HeadTrackingMode::SCREEN_RELATIVE, selector.getActualMode());
140     EXPECT_EQ(selector.getHeadToStagePose(), screenToHead.inverse() * screenToStage);
141 }
142 
TEST(ModeSelector,ScreenRelativeStaleToWorldRelative)143 TEST(ModeSelector, ScreenRelativeStaleToWorldRelative) {
144     const Pose3f screenToHead({1, 2, 3}, Quaternionf::UnitRandom());
145     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
146     const Pose3f worldToHead({7, 8, 9}, Quaternionf::UnitRandom());
147 
148     ModeSelector::Options options{.freshnessTimeout = 100};
149     ModeSelector selector(options);
150 
151     selector.setScreenToStagePose(screenToStage);
152     selector.setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
153     selector.setScreenToHeadPose(0, screenToHead);
154     selector.setWorldToHeadPose(50, worldToHead);
155     selector.setScreenStable(50, true);
156     selector.calculate(101);
157     EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
158     EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse() * screenToStage);
159 }
160 
TEST(ModeSelector,ScreenRelativeInvalidToWorldRelative)161 TEST(ModeSelector, ScreenRelativeInvalidToWorldRelative) {
162     const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
163     const Pose3f worldToHead({7, 8, 9}, Quaternionf::UnitRandom());
164 
165     ModeSelector::Options options;
166     ModeSelector selector(options);
167 
168     selector.setScreenToStagePose(screenToStage);
169 
170     selector.setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
171     selector.setScreenToHeadPose(50, std::nullopt);
172     selector.setWorldToHeadPose(50, worldToHead);
173     selector.setScreenStable(50, true);
174     selector.calculate(101);
175     EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
176     EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse() * screenToStage);
177 }
178 
179 }  // namespace
180 }  // namespace media
181 }  // namespace android
182