File: laser_segment_utils_unittest.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (290 lines) | stat: -rw-r--r-- 12,362 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/fast_ink/laser/laser_segment_utils.h"
#include "ash/test/ash_test_base.h"
#include "base/numerics/angle_conversions.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/vector2d_f.h"

namespace ash {
namespace {
// |kEpsilon| is used to check that AngleOfPointInNewCoordinates produces to
// expected angles. This function is only used after points are projected in
// opposite directions along the normal, so they should never be to close to
// each other, checking for equality up to 5 significant figures is more than
// enough.
const float kEpsilon = 0.0001f;
}  // namespace

// Helper function to check if a given |point| has the |expected_angle_degree|
// in the coordinate system formed by |origin| and |direction|.
void CheckAngleOfPointInNewCoordinates(const gfx::PointF& origin,
                                       const gfx::Vector2dF& direction,
                                       const gfx::PointF& point,
                                       float expected_angle_degree) {
  float result = AngleOfPointInNewCoordinates(origin, direction, point);
  EXPECT_NEAR(base::DegToRad(expected_angle_degree), result, kEpsilon);
}

// Helper function to check if the computed variables match the expected ones.
void CheckNormalLineVariables(const gfx::PointF& start_point,
                              const gfx::PointF& end_point,
                              float expected_slope,
                              float expected_start_intercept,
                              float expected_end_intercept) {
  float calculated_slope;
  float calculated_start_y_intercept;
  float calculated_end_y_intercept;

  ComputeNormalLineVariables(start_point, end_point, &calculated_slope,
                             &calculated_start_y_intercept,
                             &calculated_end_y_intercept);
  EXPECT_NEAR(expected_slope, calculated_slope, kEpsilon);
  EXPECT_NEAR(expected_start_intercept, calculated_start_y_intercept, kEpsilon);
  EXPECT_NEAR(expected_end_intercept, calculated_end_y_intercept, kEpsilon);
}

// Helper function to check if the a given line segment has an expected
// undefined normal line.
void CheckUndefinedNormalLine(const gfx::PointF& start_point,
                              const gfx::PointF& end_point) {
  float calculated_slope;
  float calculated_start_y_intercept;
  float calculated_end_y_intercept;

  ComputeNormalLineVariables(start_point, end_point, &calculated_slope,
                             &calculated_start_y_intercept,
                             &calculated_end_y_intercept);
  EXPECT_TRUE(std::isnan(calculated_slope));
  EXPECT_TRUE(std::isnan(calculated_start_y_intercept));
  EXPECT_TRUE(std::isnan(calculated_end_y_intercept));
}

// Helper function to check that the projections from the given line variables
// and |distance| match those expected in |expected_projections|.
void CheckProjectedPoints(const gfx::PointF& start_point,
                          float slope,
                          float y_intercept,
                          float distance,
                          std::vector<gfx::PointF>& expected_projections) {
  // There can only be two projections.
  EXPECT_EQ(2u, expected_projections.size());

  gfx::PointF calculated_first_projection;
  gfx::PointF calculated_second_projection;

  ComputeProjectedPoints(start_point, slope, y_intercept, distance,
                         &calculated_first_projection,
                         &calculated_second_projection);

  std::vector<gfx::PointF> calculated_projections = {
      calculated_first_projection, calculated_second_projection};

  // Sort the points, so that we do not have to enter the projections in the
  // right order.
  std::sort(calculated_projections.begin(), calculated_projections.end());
  std::sort(expected_projections.begin(), expected_projections.end());

  EXPECT_EQ(expected_projections[0], calculated_projections[0]);
  EXPECT_EQ(expected_projections[1], calculated_projections[1]);
}

// Helper function that checks that an IsFirstPointSmallerAngle will return
// false if |larger_angle_point| is the first point argument and return true if
// |larger_angle_point| is the second point argument.
void CheckFirstPointSmaller(const gfx::PointF& start_point,
                            const gfx::PointF& end_point,
                            const gfx::PointF& larger_angle_point,
                            const gfx::PointF& smaller_angle_point) {
  EXPECT_FALSE(IsFirstPointSmallerAngle(
      start_point, end_point, larger_angle_point, smaller_angle_point));
  EXPECT_TRUE(IsFirstPointSmallerAngle(
      start_point, end_point, smaller_angle_point, larger_angle_point));
}

using LaserSegmentUtilsTest = testing::Test;

TEST_F(LaserSegmentUtilsTest, AngleOfPointInNewCoordinates) {
  {
    // Verify angles remain the same if the origin is at (0, 0) and the
    // direction remains the same (1, 0).
    const gfx::PointF origin(0.0f, 0.0f);
    const gfx::Vector2dF direction(1.0f, 0.0f);

    // The functions range is (-180.0, 180.0).
    for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
      float rad = base::DegToRad(angle);
      gfx::PointF new_point(cos(rad), sin(rad));
      CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
    }
  }
  {
    // Verify angles are shifted by 45 degrees if the origin is at (0, 0) and
    // the direction is (1, 1).
    const gfx::PointF origin(0.0f, 0.0f);
    const gfx::Vector2dF direction(1.0f, 1.0f);

    // The functions range is (-180.0, 180.0).
    for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
      float rad = base::DegToRad(angle + 45.0f);
      gfx::PointF new_point(cos(rad), sin(rad));
      CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
    }
  }
  {
    // Verify angles remain the same if the points are translated by (1, 1),
    // if the origin is at (1, 1) and the direction remains the same (1, 0).
    const gfx::PointF origin(1.0f, 1.0f);
    const gfx::Vector2dF direction(1.0f, 0.0f);

    // The functions range is (-180.0f, 180.0f).
    for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
      float rad = base::DegToRad(angle);
      gfx::PointF new_point(cos(rad) + origin.x(), sin(rad) + origin.y());
      CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
    }
  }
  {
    // Verify angles are shifted by 45 degress if the points are translated by
    // (1, 1), if the origin is at (1, 1) and the direction remains the same
    // (1, 0).
    const gfx::PointF origin(1.0f, 1.0f);
    const gfx::Vector2dF direction(1.0f, 1.0f);

    // The functions range is (-180.0, 180.0).
    for (float angle = -179.0f; angle < 180.0f; angle += 10.0f) {
      float rad = base::DegToRad(angle + 45.0f);
      gfx::PointF new_point(cos(rad) + origin.x(), sin(rad) + origin.y());
      CheckAngleOfPointInNewCoordinates(origin, direction, new_point, angle);
    }
  }
}

TEST_F(LaserSegmentUtilsTest, ComputeNormalLineVariables) {
  {
    // Verify a line y=x should have a normal line y=-x+b. At point (0,0), b
    // should equal y+x = 0. At point (1,1), b should equal y+x = 2.
    const gfx::PointF start(0.0f, 0.0f);
    const gfx::PointF end(1.0f, 1.0f);
    float slope = -1.0f;
    float start_intercept = 0.0f;
    float end_intercept = 2.0f;
    CheckNormalLineVariables(start, end, slope, start_intercept, end_intercept);
  }
  {
    // Verify a line y=-x should have a normal line y=x+b. At point 0.0f), b
    // should equal y-x =.0f. At point (1,-1), b should equal y-x = -2.
    const gfx::PointF start(0.0f, 0.0f);
    const gfx::PointF end(1.0f, -1.0f);
    float slope = 1.0f;
    float start_intercept = 0.0f;
    float end_intercept = -2.0f;
    CheckNormalLineVariables(start, end, slope, start_intercept, end_intercept);
  }
  {
    // Verify a line x=5 should have a normal line y.0f with intercepts at the
    // previous y point.
    const gfx::PointF start(5.0f, 0.0f);
    const gfx::PointF end(5.0f, 5.0f);
    float slope = 0.0f;
    float start_intercept = 0.0f;
    float end_intercept = 5.0f;
    CheckNormalLineVariables(start, end, slope, start_intercept, end_intercept);
  }
  {
    // Verify a line parallel to the x-axis should be undefined. The line values
    // should not matter.
    const gfx::PointF start(0.0f, 5.0f);
    const gfx::PointF end(5.0f, 5.0f);
    CheckUndefinedNormalLine(start, end);
  }
}

TEST_F(LaserSegmentUtilsTest, ComputeProjectedPoints) {
  {
    // Verify projecting along y=x from (0, 0) by distance sqrt(2) should result
    // in two projections: (1, 1) and (-1, -1). We start from (0, 0) and
    // translate by (1, 1) and (-1, -1) (vectors with slope 1) to get to (1, 1)
    // and (-1, -1). The length of the distance from (1, 1) is sqrt(1*1 + 1*1) =
    // sqrt(2).
    const gfx::PointF start(0.0f, 0.0f);
    const float slope = 1.0f;
    const float y_intercept = 0.0f;
    const float distance = sqrt(2.0f);
    std::vector<gfx::PointF> expected_projections = {gfx::PointF(1.0f, 1.0f),
                                                     gfx::PointF(-1.0f, -1.0f)};
    CheckProjectedPoints(start, slope, y_intercept, distance,
                         expected_projections);
  }
  {
    // Verify projecting along y=-2x+2 from (2, -2) by distance 2*sqrt(5) should
    // result in two projections: (0, 2) and (4, -6). We start from (2, -2) and
    // translate by (-2, 4) and (2, -4) (vectors with slope -2) to get (0, 2)
    // and (4, -6). The length of the distance from (2, -2) is sqrt(2*2 + 4*4) =
    // sqrt(20) = 2*sqrt(5).
    const gfx::PointF start(2.0f, -2.0f);
    const float slope = -2.0f;
    const float y_intercept = 2.0f;
    const float distance = 2.0f * sqrt(5.0f);
    std::vector<gfx::PointF> expected_projections = {gfx::PointF(0.0f, 2.0f),
                                                     gfx::PointF(4.0f, -6.0f)};
    CheckProjectedPoints(start, slope, y_intercept, distance,
                         expected_projections);
  }
  {
    // Verify projecting along y=5 from (5,5) by distance 2 should
    // result in two projections: (5,7) and (5,3).
    const gfx::PointF start(5.0f, 5.0f);
    const float slope = 0.0f;
    const float y_intercept = 5.0f;
    const float distance = 2.0f;
    std::vector<gfx::PointF> expected_projections = {gfx::PointF(7.0f, 5.0f),
                                                     gfx::PointF(3.0f, 5.0f)};
    CheckProjectedPoints(start, slope, y_intercept, distance,
                         expected_projections);
  }
}

TEST_F(LaserSegmentUtilsTest, IsFirstPointSmallerAngle) {
  {
    // Verify this function works in the case direction is unchanged.
    const gfx::PointF start_point(0.0f, 0.0f);
    const gfx::PointF end_point(1.0f, 0.0f);
    const gfx::PointF positive_angle(1.0f, 1.0f);
    const gfx::PointF negative_angle(-1.0f, -1.0f);
    CheckFirstPointSmaller(start_point, end_point, positive_angle,
                           negative_angle);
  }
  {
    // Verify this function works in the case direction is 90 degrees.
    const gfx::PointF start_point(0.0f, 0.0f);
    const gfx::PointF end_point(0.0f, 1.0f);
    const gfx::PointF positive_angle(-1.0f, 0.0f);
    const gfx::PointF negative_angle(1.0f, 0.0f);
    CheckFirstPointSmaller(start_point, end_point, positive_angle,
                           negative_angle);
  }
  {
    // Verify this function works in the case direction is 45 degrees.
    const gfx::PointF start_point(0.0f, 0.0f);
    const gfx::PointF end_point(1.0f, 1.0f);
    const gfx::PointF positive_angle(0.0f, 1.0f);
    const gfx::PointF negative_angle(1.0f, 0.0f);
    CheckFirstPointSmaller(start_point, end_point, positive_angle,
                           negative_angle);
  }
  {
    // Verify this function works in the case direction is -135 degrees.
    const gfx::PointF start_point(0.0f, 0.0f);
    const gfx::PointF end_point(-1.0f, -1.0f);
    const gfx::PointF positive_angle(0.0f, -1.0f);
    const gfx::PointF negative_angle(-1.0f, 0.0f);
    CheckFirstPointSmaller(start_point, end_point, positive_angle,
                           negative_angle);
  }
}

}  // namespace ash