| Flutter Impeller |

point_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "flutter/impeller/geometry/point.h"
6
7 #include "flutter/impeller/geometry/geometry_asserts.h"
8 #include "gtest/gtest.h"
9
10 namespace impeller {
11 namespace testing {
12
13 TEST(PointTest, Length) {
14 for (int i = 0; i < 21; i++) {
15 EXPECT_EQ(Point(i, 0).GetLengthSquared(), i * i) << "i: " << i;
16 EXPECT_EQ(Point(0, i).GetLengthSquared(), i * i) << "i: " << i;
17 EXPECT_EQ(Point(-i, 0).GetLengthSquared(), i * i) << "i: " << i;
18 EXPECT_EQ(Point(0, -i).GetLengthSquared(), i * i) << "i: " << i;
19
20 EXPECT_EQ(Point(i, 0).GetLength(), i) << "i: " << i;
21 EXPECT_EQ(Point(0, i).GetLength(), i) << "i: " << i;
22 EXPECT_EQ(Point(-i, 0).GetLength(), i) << "i: " << i;
23 EXPECT_EQ(Point(0, -i).GetLength(), i) << "i: " << i;
24
25 EXPECT_EQ(Point(i, i).GetLengthSquared(), 2 * i * i) << "i: " << i;
26 EXPECT_EQ(Point(-i, i).GetLengthSquared(), 2 * i * i) << "i: " << i;
27 EXPECT_EQ(Point(i, -i).GetLengthSquared(), 2 * i * i) << "i: " << i;
28 EXPECT_EQ(Point(-i, -i).GetLengthSquared(), 2 * i * i) << "i: " << i;
29
30 EXPECT_FLOAT_EQ(Point(i, i).GetLength(), kSqrt2 * i) << "i: " << i;
31 EXPECT_FLOAT_EQ(Point(-i, i).GetLength(), kSqrt2 * i) << "i: " << i;
32 EXPECT_FLOAT_EQ(Point(i, -i).GetLength(), kSqrt2 * i) << "i: " << i;
33 EXPECT_FLOAT_EQ(Point(-i, -i).GetLength(), kSqrt2 * i) << "i: " << i;
34 }
35 }
36
37 TEST(PointTest, Distance) {
38 for (int j = 0; j < 21; j++) {
39 for (int i = 0; i < 21; i++) {
40 {
41 Scalar d = i - j;
42
43 EXPECT_EQ(Point(i, 0).GetDistanceSquared(Point(j, 0)), d * d)
44 << "i: " << i << ", j: " << j;
45 EXPECT_EQ(Point(0, i).GetDistanceSquared(Point(0, j)), d * d)
46 << "i: " << i << ", j: " << j;
47 EXPECT_EQ(Point(j, 0).GetDistanceSquared(Point(i, 0)), d * d)
48 << "i: " << i << ", j: " << j;
49 EXPECT_EQ(Point(0, j).GetDistanceSquared(Point(0, i)), d * d)
50 << "i: " << i << ", j: " << j;
51
52 EXPECT_EQ(Point(i, 0).GetDistance(Point(j, 0)), std::abs(d))
53 << "i: " << i << ", j: " << j;
54 EXPECT_EQ(Point(0, i).GetDistance(Point(0, j)), std::abs(d))
55 << "i: " << i << ", j: " << j;
56 EXPECT_EQ(Point(j, 0).GetDistance(Point(i, 0)), std::abs(d))
57 << "i: " << i << ", j: " << j;
58 EXPECT_EQ(Point(0, j).GetDistance(Point(0, i)), std::abs(d))
59 << "i: " << i << ", j: " << j;
60 }
61
62 {
63 Scalar d_squared = i * i + j * j;
64
65 EXPECT_EQ(Point(i, 0).GetDistanceSquared(Point(0, j)), d_squared)
66 << "i: " << i << ", j: " << j;
67 EXPECT_EQ(Point(-i, 0).GetDistanceSquared(Point(0, j)), d_squared)
68 << "i: " << i << ", j: " << j;
69 EXPECT_EQ(Point(i, 0).GetDistanceSquared(Point(0, -j)), d_squared)
70 << "i: " << i << ", j: " << j;
71 EXPECT_EQ(Point(-i, 0).GetDistanceSquared(Point(0, -j)), d_squared)
72 << "i: " << i << ", j: " << j;
73
74 Scalar d = std::sqrt(d_squared);
75
76 EXPECT_FLOAT_EQ(Point(i, 0).GetDistance(Point(0, j)), d)
77 << "i: " << i << ", j: " << j;
78 EXPECT_FLOAT_EQ(Point(-i, 0).GetDistance(Point(0, j)), d)
79 << "i: " << i << ", j: " << j;
80 EXPECT_FLOAT_EQ(Point(i, 0).GetDistance(Point(0, -j)), d)
81 << "i: " << i << ", j: " << j;
82 EXPECT_FLOAT_EQ(Point(-i, 0).GetDistance(Point(0, -j)), d)
83 << "i: " << i << ", j: " << j;
84 }
85 }
86 }
87 }
88
89 TEST(PointTest, PerpendicularLeft) {
90 EXPECT_EQ(Point(1, 0).PerpendicularLeft(), Point(0, -1));
91 EXPECT_EQ(Point(0, 1).PerpendicularLeft(), Point(1, 0));
92 EXPECT_EQ(Point(-1, 0).PerpendicularLeft(), Point(0, 1));
93 EXPECT_EQ(Point(0, -1).PerpendicularLeft(), Point(-1, 0));
94
95 EXPECT_EQ(Point(1, 1).PerpendicularLeft(), Point(1, -1));
96 EXPECT_EQ(Point(-1, 1).PerpendicularLeft(), Point(1, 1));
97 EXPECT_EQ(Point(-1, -1).PerpendicularLeft(), Point(-1, 1));
98 EXPECT_EQ(Point(1, -1).PerpendicularLeft(), Point(-1, -1));
99 }
100
101 TEST(PointTest, PerpendicularRight) {
102 EXPECT_EQ(Point(1, 0).PerpendicularRight(), Point(0, 1));
103 EXPECT_EQ(Point(0, 1).PerpendicularRight(), Point(-1, 0));
104 EXPECT_EQ(Point(-1, 0).PerpendicularRight(), Point(0, -1));
105 EXPECT_EQ(Point(0, -1).PerpendicularRight(), Point(1, 0));
106
107 EXPECT_EQ(Point(1, 1).PerpendicularRight(), Point(-1, 1));
108 EXPECT_EQ(Point(-1, 1).PerpendicularRight(), Point(-1, -1));
109 EXPECT_EQ(Point(-1, -1).PerpendicularRight(), Point(1, -1));
110 EXPECT_EQ(Point(1, -1).PerpendicularRight(), Point(1, 1));
111 }
112
113 namespace {
114 typedef std::pair<Scalar, Scalar> PtSegmentDistanceFunc(Point);
115
116 void TestPointToSegmentGroup(Point segment0,
117 Point segment1,
118 Point p0,
119 Point delta,
120 int count,
121 PtSegmentDistanceFunc calc_distance) {
122 for (int i = 0; i < count; i++) {
123 auto [distance, squared] = calc_distance(p0);
124 EXPECT_FLOAT_EQ(p0.GetDistanceToSegmentSquared(segment0, segment1), squared)
125 << p0 << " => [" << segment0 << ", " << segment1 << "]";
126 EXPECT_FLOAT_EQ(p0.GetDistanceToSegmentSquared(segment1, segment0), squared)
127 << p0 << " => [" << segment0 << ", " << segment1 << "]";
128 EXPECT_FLOAT_EQ(p0.GetDistanceToSegment(segment0, segment1), distance)
129 << p0 << " => [" << segment0 << ", " << segment1 << "]";
130 EXPECT_FLOAT_EQ(p0.GetDistanceToSegment(segment1, segment0), distance)
131 << p0 << " => [" << segment0 << ", " << segment1 << "]";
132 p0 += delta;
133 }
134 }
135 } // namespace
136
137 TEST(PointTest, PointToSegment) {
138 // Horizontal segment and points to the left of it on the same line.
139 TestPointToSegmentGroup(
140 // Segment
141 {10, 10}, {20, 10},
142 // Starting point, delta, count ({0,10} through {10,10})
143 {0, 10}, {1, 0}, 11,
144 // Distance computation
145 [](Point p) {
146 Scalar d = 10 - p.x;
147 return std::make_pair(d, d * d);
148 });
149
150 // Horizontal segment and points on the segment.
151 TestPointToSegmentGroup(
152 // Segment
153 {10, 10}, {20, 10},
154 // Starting point, delta, count ({11,10} through {19, 10})
155 {11, 10}, {1, 0}, 9,
156 // Distance computation
157 [](Point p) { //
158 return std::make_pair(0.0f, 0.0f);
159 });
160
161 // Horizontal segment and points to the right of it on the same line.
162 TestPointToSegmentGroup(
163 // Segment
164 {10, 10}, {20, 10},
165 // Starting point, delta, count ({20,10} through {30,10})
166 {20, 10}, {1, 0}, 11,
167 // Distance computation
168 [](Point p) {
169 Scalar d = p.x - 20;
170 return std::make_pair(d, d * d);
171 });
172
173 // Vertical segment and points above the top of it on the same line.
174 TestPointToSegmentGroup(
175 // Segment
176 {10, 10}, {10, 20},
177 // Starting point, delta, count ({10,0} through {10,10})
178 {10, 0}, {0, 1}, 11,
179 // Distance computation
180 [](Point p) {
181 Scalar d = 10 - p.y;
182 return std::make_pair(d, d * d);
183 });
184
185 // Vertical segment and points on the segment.
186 TestPointToSegmentGroup(
187 // Segment
188 {10, 10}, {10, 20},
189 // Starting point, delta, count ({10,11} through {10, 19})
190 {10, 11}, {0, 1}, 9,
191 // Distance computation
192 [](Point p) { //
193 return std::make_pair(0.0f, 0.0f);
194 });
195
196 // Vertical segment and points below the bottom of it on the same line.
197 TestPointToSegmentGroup(
198 // Segment
199 {10, 10}, {10, 20},
200 // Starting point, delta, count ({10,20} through {10,30})
201 {10, 20}, {0, 1}, 11,
202 // Distance computation
203 [](Point p) {
204 Scalar d = p.y - 20;
205 return std::make_pair(d, d * d);
206 });
207
208 // Horizontal segment and points 5 pixels above and to the left of it
209 // on the same line.
210 TestPointToSegmentGroup(
211 // Segment
212 {10, 10}, {20, 10},
213 // Starting point, delta, count ({0,5} through {10,5})
214 {0, 5}, {1, 0}, 11,
215 // Distance computation
216 [](Point p) {
217 Scalar d_sq = (10 - p.x) * (10 - p.x) + 25;
218 return std::make_pair(std::sqrt(d_sq), d_sq);
219 });
220
221 // Horizontal segment and points 5 pixels directly above the segment.
222 TestPointToSegmentGroup(
223 // Segment
224 {10, 10}, {20, 10},
225 // Starting point, delta, count ({11,5} through {19, 5})
226 {11, 5}, {1, 0}, 9,
227 // Distance computation
228 [](Point p) { //
229 return std::make_pair(5.0f, 25.0f);
230 });
231
232 // Horizontal segment and points 5 pixels above and to the right of it
233 // on the same line.
234 TestPointToSegmentGroup(
235 // Segment
236 {10, 10}, {20, 10},
237 // Starting point, delta, count ({20,5} through {30,5})
238 {20, 5}, {1, 0}, 11,
239 // Distance computation
240 [](Point p) {
241 Scalar d_sq = (p.x - 20) * (p.x - 20) + 25;
242 return std::make_pair(std::sqrt(d_sq), d_sq);
243 });
244
245 // Vertical segment and points 5 pixels to the left and above the segment
246 // on the same line.
247 TestPointToSegmentGroup(
248 // Segment
249 {10, 10}, {10, 20},
250 // Starting point, delta, count ({5,0} through {5,10})
251 {5, 0}, {0, 1}, 11,
252 // Distance computation
253 [](Point p) {
254 Scalar d_sq = 25 + (10 - p.y) * (10 - p.y);
255 return std::make_pair(std::sqrt(d_sq), d_sq);
256 });
257
258 // Vertical segment and points 5 pixels directly to the left of the segment.
259 TestPointToSegmentGroup(
260 // Segment
261 {10, 10}, {10, 20},
262 // Starting point, delta, count ({5,11} through {5,19,})
263 {5, 11}, {0, 1}, 9,
264 // Distance computation
265 [](Point p) { //
266 return std::make_pair(5.0f, 25.0f);
267 });
268
269 // Vertical segment and points 5 pixels to the left and below the segment
270 // on the same line.
271 TestPointToSegmentGroup(
272 // Segment
273 {10, 10}, {10, 20},
274 // Starting point, delta, count ({20,5} through {30,5})
275 {5, 20}, {0, 1}, 11,
276 // Distance computation
277 [](Point p) {
278 Scalar d_sq = 25 + (p.y - 20) * (p.y - 20);
279 return std::make_pair(std::sqrt(d_sq), d_sq);
280 });
281
282 // Diagonal segment and points up and to the right of the top of the segment.
283 TestPointToSegmentGroup(
284 // Segment
285 {10, 10}, {20, 20},
286 // Starting point, delta, count ({5,-5} through {15,5})
287 {5, -5}, {1, 1}, 11,
288 // Distance computation
289 [](Point p) {
290 Scalar d_sq = (p.x - 10) * (p.x - 10) + (p.y - 10) * (p.y - 10);
291 return std::make_pair(std::sqrt(d_sq), d_sq);
292 });
293
294 // Diagonal segment and points up and to the right of the segment itself.
295 TestPointToSegmentGroup(
296 // Segment
297 {10, 10}, {20, 20},
298 // Starting point, delta, count ({15,5} through {24,14})
299 {15, 5}, {1, 1}, 9,
300 // Distance computation
301 [](Point p) {
302 Scalar d_sq = 50.0f;
303 return std::make_pair(std::sqrt(d_sq), d_sq);
304 });
305
306 // Diagonal segment and points up and to the right of the bottom of the
307 // segment.
308 TestPointToSegmentGroup(
309 // Segment
310 {10, 10}, {20, 20},
311 // Starting point, delta, count ({25,15} through {35,25})
312 {25, 15}, {1, 1}, 11,
313 // Distance computation
314 [](Point p) {
315 Scalar d_sq = (p.x - 20) * (p.x - 20) + (p.y - 20) * (p.y - 20);
316 return std::make_pair(std::sqrt(d_sq), d_sq);
317 });
318
319 // Diagonal segment and points down and to the left of the top of the segment.
320 TestPointToSegmentGroup(
321 // Segment
322 {10, 10}, {20, 20},
323 // Starting point, delta, count ({-5,5} through {5,15})
324 {-5, 5}, {1, 1}, 11,
325 // Distance computation
326 [](Point p) {
327 Scalar d_sq = (p.x - 10) * (p.x - 10) + (p.y - 10) * (p.y - 10);
328 return std::make_pair(std::sqrt(d_sq), d_sq);
329 });
330
331 // Diagonal segment and points down and to the left of the segment itself.
332 TestPointToSegmentGroup(
333 // Segment
334 {10, 10}, {20, 20},
335 // Starting point, delta, count ({5,15} through {14,24})
336 {5, 15}, {1, 1}, 9,
337 // Distance computation
338 [](Point p) {
339 Scalar d_sq = 50.0f;
340 return std::make_pair(std::sqrt(d_sq), d_sq);
341 });
342
343 // Diagonal segment and points down and to the left of the bottom of the
344 // segment.
345 TestPointToSegmentGroup(
346 // Segment
347 {10, 10}, {20, 20},
348 // Starting point, delta, count ({15,25} through {25,35})
349 {15, 25}, {1, 1}, 11,
350 // Distance computation
351 [](Point p) {
352 Scalar d_sq = (p.x - 20) * (p.x - 20) + (p.y - 20) * (p.y - 20);
353 return std::make_pair(std::sqrt(d_sq), d_sq);
354 });
355 }
356
357 TEST(PointTest, CrossProductThreePoints) {
358 // Colinear
359 EXPECT_FLOAT_EQ(Point::Cross(Point(-1, 0), Point(0, 0), Point(1, 0)), 0);
360 EXPECT_FLOAT_EQ(Point::Cross(Point(1, 0), Point(0, 0), Point(-1, 0)), 0);
361
362 // Right turn
363 EXPECT_FLOAT_EQ(Point::Cross(Point(-1, 0), Point(0, 0), Point(0, 1)), 1);
364 EXPECT_FLOAT_EQ(Point::Cross(Point(-2, 0), Point(0, 0), Point(0, 2)), 4);
365
366 // Left turn
367 EXPECT_FLOAT_EQ(Point::Cross(Point(-1, 0), Point(0, 0), Point(0, -1)), -1);
368 EXPECT_FLOAT_EQ(Point::Cross(Point(-2, 0), Point(0, 0), Point(0, -2)), -4);
369
370 // Convenient values for a less obvious left turn.
371 // p1 - p0 == (0, 0) - (3, -4) == (-3, 4)
372 // p2 - p0 == (1, 2) - (3, -4) == (-2, 6)
373 // product of the magnitude of the 2 legs and the sin of their angle
374 // (||(-3, 4)||) * (||(-2, 6)||) * sin(angle)
375 // 5 * sqrt(40) * sin(angle)
376 // angle = arcsin(4 / 5) - arcsin(6 / sqrt(40)) ~= -18.4349
377 // sin(angle) ~= -0.316227766
378 // 5 * sqrt(40) * sin(angle) == -10
379 // The math is cleaner with the cross product:
380 // (-3 * 6) - (-2 * 4) == -18 - -8 == -10
381 EXPECT_FLOAT_EQ(Point::Cross(Point(3, -4), Point(0, 0), Point(1, 2)), -10);
382 }
383
384 } // namespace testing
385 } // namespace impeller
geometry_asserts.h
impeller::saturated::distance
SI distance
Definition: saturated_math.h:57
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::Point
TPoint< Scalar > Point
Definition: point.h:425
impeller::kSqrt2
constexpr float kSqrt2
Definition: constants.h:47
point.h
impeller::TPoint< Scalar >
impeller::TPoint::GetDistanceToSegmentSquared
Type GetDistanceToSegmentSquared(TPoint p0, TPoint p1) const
Definition: point.h:218
impeller::TPoint::GetDistanceToSegment
constexpr Type GetDistanceToSegment(TPoint p0, TPoint p1) const
Definition: point.h:281
impeller::TPoint< Scalar >::Cross
constexpr Type Cross(const TPoint &p) const
Definition: point.h:295