blob: 33f4adc5bcc18e03f7fb0e4b65f30ac938f030a7 [file] [log] [blame]
sammiequon16fd4e92016-12-07 07:02:411// Copyright (c) 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <math.h>
6
7#include "ash/laser/laser_segment_utils.h"
8#include "ash/test/ash_test_base.h"
9#include "base/memory/ptr_util.h"
10#include "ui/gfx/geometry/point.h"
11#include "ui/gfx/geometry/point_f.h"
12#include "ui/gfx/geometry/vector2d_f.h"
13
14namespace ash {
15namespace {
16// |kEpsilon| is used to check that AngleOfPointInNewCoordinates produces to
17// expected angles. This function is only used after points are projected in
18// opposite directions along the normal, so they should never be to close to
19// each other, checking for equality up to 5 significant figures is more than
20// enough.
21const float kEpsilon = 0.0001f;
22}
23
24// Helper function to check if a given |point| has the |expected_angle_degree|
25// in the coordinate system formed by |origin| and |direction|.
26void CheckAngleOfPointInNewCoordinates(const gfx::PointF& origin,
27 const gfx::Vector2dF& direction,
28 const gfx::PointF& point,
29 float expected_angle_degree) {
30 float result = AngleOfPointInNewCoordinates(origin, direction, point);
31 EXPECT_NEAR(expected_angle_degree * M_PI / 180.0f, result, kEpsilon);
32}
33
34// Helper function to check if the computed variables match the expected ones.
35void CheckNormalLineVariables(const gfx::PointF& start_point,
36 const gfx::PointF& end_point,
37 float expected_slope,
38 float expected_start_intercept,
39 float expected_end_intercept) {
40 float calculated_slope;
41 float calculated_start_y_intercept;
42 float calculated_end_y_intercept;
43
44 ComputeNormalLineVariables(start_point, end_point, &calculated_slope,
45 &calculated_start_y_intercept,
46 &calculated_end_y_intercept);
47 EXPECT_NEAR(expected_slope, calculated_slope, kEpsilon);
48 EXPECT_NEAR(expected_start_intercept, calculated_start_y_intercept, kEpsilon);
49 EXPECT_NEAR(expected_end_intercept, calculated_end_y_intercept, kEpsilon);
50}
51
52// Helper function to check if the a given line segment has an expected
53// undefined normal line.
54void CheckUndefinedNormalLine(const gfx::PointF& start_point,
55 const gfx::PointF& end_point) {
56 float calculated_slope;
57 float calculated_start_y_intercept;
58 float calculated_end_y_intercept;
59
60 ComputeNormalLineVariables(start_point, end_point, &calculated_slope,
61 &calculated_start_y_intercept,
62 &calculated_end_y_intercept);
63 EXPECT_TRUE(isnan(calculated_slope));
64 EXPECT_TRUE(isnan(calculated_start_y_intercept));
65 EXPECT_TRUE(isnan(calculated_end_y_intercept));
66}
67
68// Helper function to check that the projections from the given line variables
69// and |distance| match those expected in |expected_projections|.
70void CheckProjectedPoints(const gfx::PointF& start_point,
71 float slope,
72 float y_intercept,
73 float distance,
74 std::vector<gfx::PointF>& expected_projections) {
75 // There can only be two projections.
76 EXPECT_EQ(2u, expected_projections.size());
77
78 gfx::PointF calculated_first_projection;
79 gfx::PointF calculated_second_projection;
80
81 ComputeProjectedPoints(start_point, slope, y_intercept, distance,
82 &calculated_first_projection,
83 &calculated_second_projection);
84
85 std::vector<gfx::PointF> calculated_projections = {
86 calculated_first_projection, calculated_second_projection};
87
88 // Sort the points, so that we do not have to enter the projections in the
89 // right order.
90 std::sort(calculated_projections.begin(), calculated_projections.end());
91 std::sort(expected_projections.begin(), expected_projections.end());
92
93 EXPECT_EQ(expected_projections[0], calculated_projections[0]);
94 EXPECT_EQ(expected_projections[1], calculated_projections[1]);
95}
96
97// Helper function that checks that an IsFirstPointSmallerAngle will return
98// false if |larger_angle_point| is the first point argument and return true if
99// |larger_angle_point| is the second point argument.
100void CheckFirstPointSmaller(const gfx::PointF& start_point,
101 const gfx::PointF& end_point,
102 const gfx::PointF& larger_angle_point,
103 const gfx::PointF& smaller_angle_point) {
104 EXPECT_FALSE(IsFirstPointSmallerAngle(
105 start_point, end_point, larger_angle_point, smaller_angle_point));
106 EXPECT_TRUE(IsFirstPointSmallerAngle(
107 start_point, end_point, smaller_angle_point, larger_angle_point));
108}
109
110using LaserSegmentUtilsTest = testing::Test;
111
112TEST_F(LaserSegmentUtilsTest, AngleOfPointInNewCoordinates) {
113 {
114 // Verify angles remain the same if the origin is at (0, 0) and the
115 // direction remains the same (1, 0).
116 const gfx::PointF origin(0.0f, 0.0f);
117 const gfx::Vector2dF direction(1.0f, 0.0f);
118
119 // The functions range is (-180.0, 180.0).
120 for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
121 float rad = angle * M_PI / 180.0f;
122 gfx::PointF new_point(cos(rad), sin(rad));
123 CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
124 }
125 }
126 {
127 // Verify angles are shifted by 45 degrees if the origin is at (0, 0) and
128 // the direction is (1, 1).
129 const gfx::PointF origin(0.0f, 0.0f);
130 const gfx::Vector2dF direction(1.0f, 1.0f);
131
132 // The functions range is (-180.0, 180.0).
133 for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
134 float rad = (angle + 45.0f) * M_PI / 180.0f;
135 gfx::PointF new_point(cos(rad), sin(rad));
136 CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
137 }
138 }
139 {
140 // Verify angles remain the same if the points are translated by (1, 1),
141 // if the origin is at (1, 1) and the direction remains the same (1, 0).
142 const gfx::PointF origin(1.0f, 1.0f);
143 const gfx::Vector2dF direction(1.0f, 0.0f);
144
145 // The functions range is (-180.0f, 180.0f).
146 for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
147 float rad = angle * M_PI / 180.0f;
148 gfx::PointF new_point(cos(rad) + origin.x(), sin(rad) + origin.y());
149 CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
150 }
151 }
152 {
153 // Verify angles are shifted by 45 degress if the points are translated by
154 // (1, 1), if the origin is at (1, 1) and the direction remains the same
155 // (1, 0).
156 const gfx::PointF origin(1.0f, 1.0f);
157 const gfx::Vector2dF direction(1.0f, 1.0f);
158
159 // The functions range is (-180.0, 180.0).
160 for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
161 float rad = (angle + 45.0f) * M_PI / 180.0f;
162 gfx::PointF new_point(cos(rad) + origin.x(), sin(rad) + origin.y());
163 CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
164 }
165 }
166}
167
168TEST_F(LaserSegmentUtilsTest, ComputeNormalLineVariables) {
169 {
170 // Verify a line y=x should have a normal line y=-x+b. At point (0,0), b
171 // should equal y+x = 0. At point (1,1), b shoudl equal y+x = 2.
172 const gfx::PointF start(0.0f, 0.0f);
173 const gfx::PointF end(1.0f, 1.0f);
174 float slope = -1.0f;
175 float start_intercept = 0.0f;
176 float end_intercept = 2.0f;
177 CheckNormalLineVariables(start, end, slope, start_intercept, end_intercept);
178 }
179 {
180 // Verify a line y=-x should have a normal line y=x+b. At point 0.0f), b
181 // should equal y-x =.0f. At point (1,-1), b should equal y-x = -2.
182 const gfx::PointF start(0.0f, 0.0f);
183 const gfx::PointF end(1.0f, -1.0f);
184 float slope = 1.0f;
185 float start_intercept = 0.0f;
186 float end_intercept = -2.0f;
187 CheckNormalLineVariables(start, end, slope, start_intercept, end_intercept);
188 }
189 {
190 // Verify a line x=5 should have a normal line y.0f with intercepts at the
191 // previous y point.
192 const gfx::PointF start(5.0f, 0.0f);
193 const gfx::PointF end(5.0f, 5.0f);
194 float slope = 0.0f;
195 float start_intercept = 0.0f;
196 float end_intercept = 5.0f;
197 CheckNormalLineVariables(start, end, slope, start_intercept, end_intercept);
198 }
199 {
200 // Verify a line parallel to the x-axis should be undefined. The line values
201 // should not matter.
202 const gfx::PointF start(0.0f, 5.0f);
203 const gfx::PointF end(5.0f, 5.0f);
204 CheckUndefinedNormalLine(start, end);
205 }
206}
207
208TEST_F(LaserSegmentUtilsTest, ComputeProjectedPoints) {
209 {
210 // Verify projecting along y=x from (0, 0) by distance sqrt(2) shoudl result
211 // in two projections: (1, 1) and (-1, -1). We start from (0, 0) and
212 // translate by (1, 1) and (-1, -1) (vectors with slope 1) to get to (1, 1)
213 // and (-1, -1). The length of the distance from (1, 1) is sqrt(1*1 + 1*1) =
214 // sqrt(2).
215 const gfx::PointF start(0.0f, 0.0f);
216 const float slope = 1.0f;
217 const float y_intercept = 0.0f;
218 const float distance = sqrt(2.0f);
219 std::vector<gfx::PointF> expected_projections = {gfx::PointF(1.0f, 1.0f),
220 gfx::PointF(-1.0f, -1.0f)};
221 CheckProjectedPoints(start, slope, y_intercept, distance,
222 expected_projections);
223 }
224 {
225 // Verify projecting along y=-2x+2 from (2, -2) by distance 2*sqrt(5) should
226 // result in two projections: (0, 2) and (4, -6). We start from (2, -2) and
227 // translate by (-2, 4) and (2, -4) (vectors with slope -2) to get (0, 2)
228 // and (4, -6). The length of the distance from (2, -2) is sqrt(2*2 + 4*4) =
229 // sqrt(20) = 2*sqrt(5).
230 const gfx::PointF start(2.0f, -2.0f);
231 const float slope = -2.0f;
232 const float y_intercept = 2.0f;
233 const float distance = 2.0f * sqrt(5.0f);
234 std::vector<gfx::PointF> expected_projections = {gfx::PointF(0.0f, 2.0f),
235 gfx::PointF(4.0f, -6.0f)};
236 CheckProjectedPoints(start, slope, y_intercept, distance,
237 expected_projections);
238 }
239 {
240 // Verify projecting along y=5 from (5,5) by distance 2 should
241 // result in two projections: (5,7) and (5,3).
242 const gfx::PointF start(5.0f, 5.0f);
243 const float slope = 0.0f;
244 const float y_intercept = 5.0f;
245 const float distance = 2.0f;
246 std::vector<gfx::PointF> expected_projections = {gfx::PointF(7.0f, 5.0f),
247 gfx::PointF(3.0f, 5.0f)};
248 CheckProjectedPoints(start, slope, y_intercept, distance,
249 expected_projections);
250 }
251}
252
253TEST_F(LaserSegmentUtilsTest, IsFirstPointSmallerAngle) {
254 {
255 // Verify this function works in the case direction is unchanged.
256 const gfx::PointF start_point(0.0f, 0.0f);
257 const gfx::PointF end_point(1.0f, 0.0f);
258 const gfx::PointF positive_angle(1.0f, 1.0f);
259 const gfx::PointF negative_angle(-1.0f, -1.0f);
260 CheckFirstPointSmaller(start_point, end_point, positive_angle,
261 negative_angle);
262 }
263 {
264 // Verify this function works in the case direction is 90 degrees.
265 const gfx::PointF start_point(0.0f, 0.0f);
266 const gfx::PointF end_point(0.0f, 1.0f);
267 const gfx::PointF positive_angle(-1.0f, 0.0f);
268 const gfx::PointF negative_angle(1.0f, 0.0f);
269 CheckFirstPointSmaller(start_point, end_point, positive_angle,
270 negative_angle);
271 }
272 {
273 // Verify this function works in the case direction is 45 degrees.
274 const gfx::PointF start_point(0.0f, 0.0f);
275 const gfx::PointF end_point(1.0f, 1.0f);
276 const gfx::PointF positive_angle(0.0f, 1.0f);
277 const gfx::PointF negative_angle(1.0f, 0.0f);
278 CheckFirstPointSmaller(start_point, end_point, positive_angle,
279 negative_angle);
280 }
281 {
282 // Verify this function works in the case direction is -135 degrees.
283 const gfx::PointF start_point(0.0f, 0.0f);
284 const gfx::PointF end_point(-1.0f, -1.0f);
285 const gfx::PointF positive_angle(0.0f, -1.0f);
286 const gfx::PointF negative_angle(-1.0f, 0.0f);
287 CheckFirstPointSmaller(start_point, end_point, positive_angle,
288 negative_angle);
289 }
290}
291
292} // namespace ash