Flutter Impeller
round_superellipse_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 "gtest/gtest.h"
6 
8 
10 
11 #define CHECK_POINT_WITH_OFFSET(rr, p, outward_offset) \
12  EXPECT_TRUE(rr.Contains(p)); \
13  EXPECT_FALSE(rr.Contains(p + outward_offset));
14 
15 namespace impeller {
16 namespace testing {
17 
18 TEST(RoundSuperellipseTest, EmptyDeclaration) {
20 
21  EXPECT_TRUE(rse.IsEmpty());
22  EXPECT_FALSE(rse.IsRect());
23  EXPECT_FALSE(rse.IsOval());
24  EXPECT_TRUE(rse.IsFinite());
25  EXPECT_TRUE(rse.GetBounds().IsEmpty());
26  EXPECT_EQ(rse.GetBounds(), Rect());
27  EXPECT_EQ(rse.GetBounds().GetLeft(), 0.0f);
28  EXPECT_EQ(rse.GetBounds().GetTop(), 0.0f);
29  EXPECT_EQ(rse.GetBounds().GetRight(), 0.0f);
30  EXPECT_EQ(rse.GetBounds().GetBottom(), 0.0f);
31  EXPECT_EQ(rse.GetRadii().top_left, Size());
32  EXPECT_EQ(rse.GetRadii().top_right, Size());
33  EXPECT_EQ(rse.GetRadii().bottom_left, Size());
34  EXPECT_EQ(rse.GetRadii().bottom_right, Size());
35  EXPECT_EQ(rse.GetRadii().top_left.width, 0.0f);
36  EXPECT_EQ(rse.GetRadii().top_left.height, 0.0f);
37  EXPECT_EQ(rse.GetRadii().top_right.width, 0.0f);
38  EXPECT_EQ(rse.GetRadii().top_right.height, 0.0f);
39  EXPECT_EQ(rse.GetRadii().bottom_left.width, 0.0f);
40  EXPECT_EQ(rse.GetRadii().bottom_left.height, 0.0f);
41  EXPECT_EQ(rse.GetRadii().bottom_right.width, 0.0f);
42  EXPECT_EQ(rse.GetRadii().bottom_right.height, 0.0f);
43 }
44 
45 TEST(RoundSuperellipseTest, DefaultConstructor) {
47 
48  EXPECT_TRUE(rse.IsEmpty());
49  EXPECT_FALSE(rse.IsRect());
50  EXPECT_FALSE(rse.IsOval());
51  EXPECT_TRUE(rse.IsFinite());
52  EXPECT_TRUE(rse.GetBounds().IsEmpty());
53  EXPECT_EQ(rse.GetBounds(), Rect());
54  EXPECT_EQ(rse.GetRadii().top_left, Size());
55  EXPECT_EQ(rse.GetRadii().top_right, Size());
56  EXPECT_EQ(rse.GetRadii().bottom_left, Size());
57  EXPECT_EQ(rse.GetRadii().bottom_right, Size());
58 }
59 
60 TEST(RoundSuperellipseTest, EmptyRectConstruction) {
61  RoundSuperellipse rse =
62  RoundSuperellipse::MakeRect(Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f));
63 
64  EXPECT_TRUE(rse.IsEmpty());
65  EXPECT_FALSE(rse.IsRect());
66  EXPECT_FALSE(rse.IsOval());
67  EXPECT_TRUE(rse.IsFinite());
68  EXPECT_TRUE(rse.GetBounds().IsEmpty());
69  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f));
70  EXPECT_EQ(rse.GetRadii().top_left, Size());
71  EXPECT_EQ(rse.GetRadii().top_right, Size());
72  EXPECT_EQ(rse.GetRadii().bottom_left, Size());
73  EXPECT_EQ(rse.GetRadii().bottom_right, Size());
74 }
75 
76 TEST(RoundSuperellipseTest, RectConstructor) {
77  RoundSuperellipse rse =
78  RoundSuperellipse::MakeRect(Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
79 
80  EXPECT_FALSE(rse.IsEmpty());
81  EXPECT_TRUE(rse.IsRect());
82  EXPECT_FALSE(rse.IsOval());
83  EXPECT_TRUE(rse.IsFinite());
84  EXPECT_FALSE(rse.GetBounds().IsEmpty());
85  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
86  EXPECT_EQ(rse.GetRadii().top_left, Size());
87  EXPECT_EQ(rse.GetRadii().top_right, Size());
88  EXPECT_EQ(rse.GetRadii().bottom_left, Size());
89  EXPECT_EQ(rse.GetRadii().bottom_right, Size());
90 }
91 
92 TEST(RoundSuperellipseTest, InvertedRectConstruction) {
93  RoundSuperellipse rse =
94  RoundSuperellipse::MakeRect(Rect::MakeLTRB(20.0f, 20.0f, 10.0f, 10.0f));
95 
96  EXPECT_FALSE(rse.IsEmpty());
97  EXPECT_TRUE(rse.IsRect());
98  EXPECT_FALSE(rse.IsOval());
99  EXPECT_TRUE(rse.IsFinite());
100  EXPECT_FALSE(rse.GetBounds().IsEmpty());
101  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
102  EXPECT_EQ(rse.GetRadii().top_left, Size());
103  EXPECT_EQ(rse.GetRadii().top_right, Size());
104  EXPECT_EQ(rse.GetRadii().bottom_left, Size());
105  EXPECT_EQ(rse.GetRadii().bottom_right, Size());
106 }
107 
108 TEST(RoundSuperellipseTest, EmptyOvalConstruction) {
110  Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f), 10.0f, 10.0f);
111 
112  EXPECT_TRUE(rse.IsEmpty());
113  EXPECT_FALSE(rse.IsRect());
114  EXPECT_FALSE(rse.IsOval());
115  EXPECT_TRUE(rse.IsFinite());
116  EXPECT_TRUE(rse.GetBounds().IsEmpty());
117  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(20.0f, 20.0f, 20.0f, 20.0f));
118  EXPECT_EQ(rse.GetRadii().top_left, Size());
119  EXPECT_EQ(rse.GetRadii().top_right, Size());
120  EXPECT_EQ(rse.GetRadii().bottom_left, Size());
121  EXPECT_EQ(rse.GetRadii().bottom_right, Size());
122 }
123 
124 TEST(RoundSuperellipseTest, OvalConstructor) {
125  RoundSuperellipse rse =
126  RoundSuperellipse::MakeOval(Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
127 
128  EXPECT_FALSE(rse.IsEmpty());
129  EXPECT_FALSE(rse.IsRect());
130  EXPECT_TRUE(rse.IsOval());
131  EXPECT_TRUE(rse.IsFinite());
132  EXPECT_FALSE(rse.GetBounds().IsEmpty());
133  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
134  EXPECT_EQ(rse.GetRadii().top_left, Size(5.0f, 5.0f));
135  EXPECT_EQ(rse.GetRadii().top_right, Size(5.0f, 5.0f));
136  EXPECT_EQ(rse.GetRadii().bottom_left, Size(5.0f, 5.0f));
137  EXPECT_EQ(rse.GetRadii().bottom_right, Size(5.0f, 5.0f));
138 }
139 
140 TEST(RoundSuperellipseTest, InvertedOvalConstruction) {
142  Rect::MakeLTRB(20.0f, 20.0f, 10.0f, 10.0f), 10.0f, 10.0f);
143 
144  EXPECT_FALSE(rse.IsEmpty());
145  EXPECT_FALSE(rse.IsRect());
146  EXPECT_TRUE(rse.IsOval());
147  EXPECT_TRUE(rse.IsFinite());
148  EXPECT_FALSE(rse.GetBounds().IsEmpty());
149  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
150  EXPECT_EQ(rse.GetRadii().top_left, Size(5.0f, 5.0f));
151  EXPECT_EQ(rse.GetRadii().top_right, Size(5.0f, 5.0f));
152  EXPECT_EQ(rse.GetRadii().bottom_left, Size(5.0f, 5.0f));
153  EXPECT_EQ(rse.GetRadii().bottom_right, Size(5.0f, 5.0f));
154 }
155 
156 TEST(RoundSuperellipseTest, RectRadiusConstructor) {
158  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f), 2.0f);
159 
160  EXPECT_FALSE(rse.IsEmpty());
161  EXPECT_FALSE(rse.IsRect());
162  EXPECT_FALSE(rse.IsOval());
163  EXPECT_TRUE(rse.IsFinite());
164  EXPECT_FALSE(rse.GetBounds().IsEmpty());
165  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
166  EXPECT_EQ(rse.GetRadii().top_left, Size(2.0f, 2.0f));
167  EXPECT_EQ(rse.GetRadii().top_right, Size(2.0f, 2.0f));
168  EXPECT_EQ(rse.GetRadii().bottom_left, Size(2.0f, 2.0f));
169  EXPECT_EQ(rse.GetRadii().bottom_right, Size(2.0f, 2.0f));
170 }
171 
172 TEST(RoundSuperellipseTest, RectXYConstructor) {
174  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f), 2.0f, 3.0f);
175 
176  EXPECT_FALSE(rse.IsEmpty());
177  EXPECT_FALSE(rse.IsRect());
178  EXPECT_FALSE(rse.IsOval());
179  EXPECT_TRUE(rse.IsFinite());
180  EXPECT_FALSE(rse.GetBounds().IsEmpty());
181  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
182  EXPECT_EQ(rse.GetRadii().top_left, Size(2.0f, 3.0f));
183  EXPECT_EQ(rse.GetRadii().top_right, Size(2.0f, 3.0f));
184  EXPECT_EQ(rse.GetRadii().bottom_left, Size(2.0f, 3.0f));
185  EXPECT_EQ(rse.GetRadii().bottom_right, Size(2.0f, 3.0f));
186 }
187 
188 TEST(RoundSuperellipseTest, RectSizeConstructor) {
190  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f), Size(2.0f, 3.0f));
191 
192  EXPECT_FALSE(rse.IsEmpty());
193  EXPECT_FALSE(rse.IsRect());
194  EXPECT_FALSE(rse.IsOval());
195  EXPECT_TRUE(rse.IsFinite());
196  EXPECT_FALSE(rse.GetBounds().IsEmpty());
197  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
198  EXPECT_EQ(rse.GetRadii().top_left, Size(2.0f, 3.0f));
199  EXPECT_EQ(rse.GetRadii().top_right, Size(2.0f, 3.0f));
200  EXPECT_EQ(rse.GetRadii().bottom_left, Size(2.0f, 3.0f));
201  EXPECT_EQ(rse.GetRadii().bottom_right, Size(2.0f, 3.0f));
202 }
203 
204 TEST(RoundSuperellipseTest, RectRadiiConstructor) {
206  Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f),
207  {
208  .top_left = Size(1.0, 1.5),
209  .top_right = Size(2.0, 2.5f),
210  .bottom_left = Size(3.0, 3.5f),
211  .bottom_right = Size(4.0, 4.5f),
212  });
213 
214  EXPECT_FALSE(rse.IsEmpty());
215  EXPECT_FALSE(rse.IsRect());
216  EXPECT_FALSE(rse.IsOval());
217  EXPECT_TRUE(rse.IsFinite());
218  EXPECT_FALSE(rse.GetBounds().IsEmpty());
219  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f));
220  EXPECT_EQ(rse.GetRadii().top_left, Size(1.0f, 1.5f));
221  EXPECT_EQ(rse.GetRadii().top_right, Size(2.0f, 2.5f));
222  EXPECT_EQ(rse.GetRadii().bottom_left, Size(3.0f, 3.5f));
223  EXPECT_EQ(rse.GetRadii().bottom_right, Size(4.0f, 4.5f));
224 }
225 
226 TEST(RoundSuperellipseTest, RectRadiiOverflowWidthConstructor) {
228  Rect::MakeXYWH(10.0f, 10.0f, 6.0f, 30.0f),
229  {
230  .top_left = Size(1.0f, 2.0f),
231  .top_right = Size(3.0f, 4.0f),
232  .bottom_left = Size(5.0f, 6.0f),
233  .bottom_right = Size(7.0f, 8.0f),
234  });
235  // Largest sum of paired radii widths is the bottom edge which sums to 12
236  // Rect is only 6 wide so all radii are scaled by half
237  // Rect is 30 tall so no scaling should happen due to radii heights
238 
239  EXPECT_FALSE(rse.IsEmpty());
240  EXPECT_FALSE(rse.IsRect());
241  EXPECT_FALSE(rse.IsOval());
242  EXPECT_TRUE(rse.IsFinite());
243  EXPECT_FALSE(rse.GetBounds().IsEmpty());
244  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 16.0f, 40.0f));
245  EXPECT_EQ(rse.GetRadii().top_left, Size(0.5f, 1.0f));
246  EXPECT_EQ(rse.GetRadii().top_right, Size(1.5f, 2.0f));
247  EXPECT_EQ(rse.GetRadii().bottom_left, Size(2.5f, 3.0f));
248  EXPECT_EQ(rse.GetRadii().bottom_right, Size(3.5f, 4.0f));
249 }
250 
251 TEST(RoundSuperellipseTest, RectRadiiOverflowHeightConstructor) {
253  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 6.0f),
254  {
255  .top_left = Size(1.0f, 2.0f),
256  .top_right = Size(3.0f, 4.0f),
257  .bottom_left = Size(5.0f, 6.0f),
258  .bottom_right = Size(7.0f, 8.0f),
259  });
260  // Largest sum of paired radii heights is the right edge which sums to 12
261  // Rect is only 6 tall so all radii are scaled by half
262  // Rect is 30 wide so no scaling should happen due to radii widths
263 
264  EXPECT_FALSE(rse.IsEmpty());
265  EXPECT_FALSE(rse.IsRect());
266  EXPECT_FALSE(rse.IsOval());
267  EXPECT_TRUE(rse.IsFinite());
268  EXPECT_FALSE(rse.GetBounds().IsEmpty());
269  EXPECT_EQ(rse.GetBounds(), Rect::MakeLTRB(10.0f, 10.0f, 40.0f, 16.0f));
270  EXPECT_EQ(rse.GetRadii().top_left, Size(0.5f, 1.0f));
271  EXPECT_EQ(rse.GetRadii().top_right, Size(1.5f, 2.0f));
272  EXPECT_EQ(rse.GetRadii().bottom_left, Size(2.5f, 3.0f));
273  EXPECT_EQ(rse.GetRadii().bottom_right, Size(3.5f, 4.0f));
274 }
275 
276 TEST(RoundSuperellipseTest, Shift) {
278  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
279  {
280  .top_left = Size(1.0f, 2.0f),
281  .top_right = Size(3.0f, 4.0f),
282  .bottom_left = Size(5.0f, 6.0f),
283  .bottom_right = Size(7.0f, 8.0f),
284  });
285  RoundSuperellipse shifted = rse.Shift(5.0, 6.0);
286 
287  EXPECT_FALSE(shifted.IsEmpty());
288  EXPECT_FALSE(shifted.IsRect());
289  EXPECT_FALSE(shifted.IsOval());
290  EXPECT_TRUE(shifted.IsFinite());
291  EXPECT_FALSE(shifted.GetBounds().IsEmpty());
292  EXPECT_EQ(shifted.GetBounds(), Rect::MakeLTRB(15.0f, 16.0f, 45.0f, 46.0f));
293  EXPECT_EQ(shifted.GetRadii().top_left, Size(1.0f, 2.0f));
294  EXPECT_EQ(shifted.GetRadii().top_right, Size(3.0f, 4.0f));
295  EXPECT_EQ(shifted.GetRadii().bottom_left, Size(5.0f, 6.0f));
296  EXPECT_EQ(shifted.GetRadii().bottom_right, Size(7.0f, 8.0f));
297 
298  EXPECT_EQ(shifted, RoundSuperellipse::MakeRectRadii(
299  Rect::MakeXYWH(15.0f, 16.0f, 30.0f, 30.0f),
300  {
301  .top_left = Size(1.0f, 2.0f),
302  .top_right = Size(3.0f, 4.0f),
303  .bottom_left = Size(5.0f, 6.0f),
304  .bottom_right = Size(7.0f, 8.0f),
305  }));
306 }
307 
308 TEST(RoundSuperellipseTest, ExpandScalar) {
310  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
311  {
312  .top_left = Size(1.0f, 2.0f),
313  .top_right = Size(3.0f, 4.0f),
314  .bottom_left = Size(5.0f, 6.0f),
315  .bottom_right = Size(7.0f, 8.0f),
316  });
317  RoundSuperellipse expanded = rse.Expand(5.0);
318 
319  EXPECT_FALSE(expanded.IsEmpty());
320  EXPECT_FALSE(expanded.IsRect());
321  EXPECT_FALSE(expanded.IsOval());
322  EXPECT_TRUE(expanded.IsFinite());
323  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
324  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(5.0f, 5.0f, 45.0f, 45.0f));
325  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
326  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
327  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
328  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
329 
330  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
331  Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f),
332  {
333  .top_left = Size(1.0f, 2.0f),
334  .top_right = Size(3.0f, 4.0f),
335  .bottom_left = Size(5.0f, 6.0f),
336  .bottom_right = Size(7.0f, 8.0f),
337  }));
338 }
339 
340 TEST(RoundSuperellipseTest, ExpandTwoScalars) {
342  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
343  {
344  .top_left = Size(1.0f, 2.0f),
345  .top_right = Size(3.0f, 4.0f),
346  .bottom_left = Size(5.0f, 6.0f),
347  .bottom_right = Size(7.0f, 8.0f),
348  });
349  RoundSuperellipse expanded = rse.Expand(5.0, 6.0);
350 
351  EXPECT_FALSE(expanded.IsEmpty());
352  EXPECT_FALSE(expanded.IsRect());
353  EXPECT_FALSE(expanded.IsOval());
354  EXPECT_TRUE(expanded.IsFinite());
355  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
356  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(5.0f, 4.0f, 45.0f, 46.0f));
357  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
358  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
359  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
360  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
361 
362  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
363  Rect::MakeXYWH(5.0f, 4.0f, 40.0f, 42.0f),
364  {
365  .top_left = Size(1.0f, 2.0f),
366  .top_right = Size(3.0f, 4.0f),
367  .bottom_left = Size(5.0f, 6.0f),
368  .bottom_right = Size(7.0f, 8.0f),
369  }));
370 }
371 
372 TEST(RoundSuperellipseTest, ExpandFourScalars) {
374  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
375  {
376  .top_left = Size(1.0f, 2.0f),
377  .top_right = Size(3.0f, 4.0f),
378  .bottom_left = Size(5.0f, 6.0f),
379  .bottom_right = Size(7.0f, 8.0f),
380  });
381  RoundSuperellipse expanded = rse.Expand(5.0, 6.0, 7.0, 8.0);
382 
383  EXPECT_FALSE(expanded.IsEmpty());
384  EXPECT_FALSE(expanded.IsRect());
385  EXPECT_FALSE(expanded.IsOval());
386  EXPECT_TRUE(expanded.IsFinite());
387  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
388  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(5.0f, 4.0f, 47.0f, 48.0f));
389  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
390  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
391  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
392  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
393 
394  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
395  Rect::MakeXYWH(5.0f, 4.0f, 42.0f, 44.0f),
396  {
397  .top_left = Size(1.0f, 2.0f),
398  .top_right = Size(3.0f, 4.0f),
399  .bottom_left = Size(5.0f, 6.0f),
400  .bottom_right = Size(7.0f, 8.0f),
401  }));
402 }
403 
404 TEST(RoundSuperellipseTest, ContractScalar) {
406  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
407  {
408  .top_left = Size(1.0f, 2.0f),
409  .top_right = Size(3.0f, 4.0f),
410  .bottom_left = Size(5.0f, 6.0f),
411  .bottom_right = Size(7.0f, 8.0f),
412  });
413  RoundSuperellipse expanded = rse.Expand(-2.0);
414 
415  EXPECT_FALSE(expanded.IsEmpty());
416  EXPECT_FALSE(expanded.IsRect());
417  EXPECT_FALSE(expanded.IsOval());
418  EXPECT_TRUE(expanded.IsFinite());
419  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
420  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(12.0f, 12.0f, 38.0f, 38.0f));
421  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
422  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
423  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
424  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
425 
426  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
427  Rect::MakeXYWH(12.0f, 12.0f, 26.0f, 26.0f),
428  {
429  .top_left = Size(1.0f, 2.0f),
430  .top_right = Size(3.0f, 4.0f),
431  .bottom_left = Size(5.0f, 6.0f),
432  .bottom_right = Size(7.0f, 8.0f),
433  }));
434 }
435 
436 TEST(RoundSuperellipseTest, ContractTwoScalars) {
438  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
439  {
440  .top_left = Size(1.0f, 2.0f),
441  .top_right = Size(3.0f, 4.0f),
442  .bottom_left = Size(5.0f, 6.0f),
443  .bottom_right = Size(7.0f, 8.0f),
444  });
445  RoundSuperellipse expanded = rse.Expand(-1.0, -2.0);
446 
447  EXPECT_FALSE(expanded.IsEmpty());
448  EXPECT_FALSE(expanded.IsRect());
449  EXPECT_FALSE(expanded.IsOval());
450  EXPECT_TRUE(expanded.IsFinite());
451  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
452  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(11.0f, 12.0f, 39.0f, 38.0f));
453  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
454  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
455  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
456  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
457 
458  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
459  Rect::MakeXYWH(11.0f, 12.0f, 28.0f, 26.0f),
460  {
461  .top_left = Size(1.0f, 2.0f),
462  .top_right = Size(3.0f, 4.0f),
463  .bottom_left = Size(5.0f, 6.0f),
464  .bottom_right = Size(7.0f, 8.0f),
465  }));
466 }
467 
468 TEST(RoundSuperellipseTest, ContractFourScalars) {
470  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
471  {
472  .top_left = Size(1.0f, 2.0f),
473  .top_right = Size(3.0f, 4.0f),
474  .bottom_left = Size(5.0f, 6.0f),
475  .bottom_right = Size(7.0f, 8.0f),
476  });
477  RoundSuperellipse expanded = rse.Expand(-1.0, -1.5, -2.0, -2.5);
478 
479  EXPECT_FALSE(expanded.IsEmpty());
480  EXPECT_FALSE(expanded.IsRect());
481  EXPECT_FALSE(expanded.IsOval());
482  EXPECT_TRUE(expanded.IsFinite());
483  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
484  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(11.0f, 11.5f, 38.0f, 37.5f));
485  EXPECT_EQ(expanded.GetRadii().top_left, Size(1.0f, 2.0f));
486  EXPECT_EQ(expanded.GetRadii().top_right, Size(3.0f, 4.0f));
487  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(5.0f, 6.0f));
488  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(7.0f, 8.0f));
489 
490  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
491  Rect::MakeXYWH(11.0f, 11.5f, 27.0f, 26.0f),
492  {
493  .top_left = Size(1.0f, 2.0f),
494  .top_right = Size(3.0f, 4.0f),
495  .bottom_left = Size(5.0f, 6.0f),
496  .bottom_right = Size(7.0f, 8.0f),
497  }));
498 }
499 
500 TEST(RoundSuperellipseTest, ContractAndRequireRadiiAdjustment) {
502  Rect::MakeXYWH(10.0f, 10.0f, 30.0f, 30.0f),
503  {
504  .top_left = Size(1.0f, 2.0f),
505  .top_right = Size(3.0f, 4.0f),
506  .bottom_left = Size(5.0f, 6.0f),
507  .bottom_right = Size(7.0f, 8.0f),
508  });
509  RoundSuperellipse expanded = rse.Expand(-12.0);
510  // Largest sum of paired radii sizes are the bottom and right edges
511  // both of which sum to 12
512  // Rect was 30x30 reduced by 12 on all sides leaving only 6x6, so all
513  // radii are scaled by half to avoid overflowing the contracted rect
514 
515  EXPECT_FALSE(expanded.IsEmpty());
516  EXPECT_FALSE(expanded.IsRect());
517  EXPECT_FALSE(expanded.IsOval());
518  EXPECT_TRUE(expanded.IsFinite());
519  EXPECT_FALSE(expanded.GetBounds().IsEmpty());
520  EXPECT_EQ(expanded.GetBounds(), Rect::MakeLTRB(22.0f, 22.0f, 28.0f, 28.0f));
521  EXPECT_EQ(expanded.GetRadii().top_left, Size(0.5f, 1.0f));
522  EXPECT_EQ(expanded.GetRadii().top_right, Size(1.5f, 2.0f));
523  EXPECT_EQ(expanded.GetRadii().bottom_left, Size(2.5f, 3.0f));
524  EXPECT_EQ(expanded.GetRadii().bottom_right, Size(3.5f, 4.0f));
525 
526  // In this test, the MakeRectRadii constructor will make the same
527  // adjustment to the radii that the Expand method applied.
528  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
529  Rect::MakeXYWH(22.0f, 22.0f, 6.0f, 6.0f),
530  {
531  .top_left = Size(1.0f, 2.0f),
532  .top_right = Size(3.0f, 4.0f),
533  .bottom_left = Size(5.0f, 6.0f),
534  .bottom_right = Size(7.0f, 8.0f),
535  }));
536 
537  // In this test, the arguments to the constructor supply the correctly
538  // adjusted radii (though there is no real way to tell other than
539  // the result is the same).
540  EXPECT_EQ(expanded, RoundSuperellipse::MakeRectRadii(
541  Rect::MakeXYWH(22.0f, 22.0f, 6.0f, 6.0f),
542  {
543  .top_left = Size(0.5f, 1.0f),
544  .top_right = Size(1.5f, 2.0f),
545  .bottom_left = Size(2.5f, 3.0f),
546  .bottom_right = Size(3.5f, 4.0f),
547  }));
548 }
549 
550 TEST(RoundSuperellipseTest, NoCornerRoundSuperellipseContains) {
551  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
552  // Rounded superellipses of bounds with no corners contains corners just
553  // barely.
554  auto no_corners = RoundSuperellipse::MakeRectRadii(
555  bounds, RoundingRadii::MakeRadii({0.0f, 0.0f}));
556 
557  EXPECT_TRUE(no_corners.Contains({-50, -50}));
558  // Rectangles have half-in, half-out containment so we need
559  // to be careful about testing containment of right/bottom corners.
560  EXPECT_TRUE(no_corners.Contains({-50, 49.99}));
561  EXPECT_TRUE(no_corners.Contains({49.99, -50}));
562  EXPECT_TRUE(no_corners.Contains({49.99, 49.99}));
563  EXPECT_FALSE(no_corners.Contains({-50.01, -50}));
564  EXPECT_FALSE(no_corners.Contains({-50, -50.01}));
565  EXPECT_FALSE(no_corners.Contains({-50.01, 50}));
566  EXPECT_FALSE(no_corners.Contains({-50, 50.01}));
567  EXPECT_FALSE(no_corners.Contains({50.01, -50}));
568  EXPECT_FALSE(no_corners.Contains({50, -50.01}));
569  EXPECT_FALSE(no_corners.Contains({50.01, 50}));
570  EXPECT_FALSE(no_corners.Contains({50, 50.01}));
571 }
572 
573 TEST(RoundSuperellipseTest, TinyCornerContains) {
574  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
575  // Rounded superellipses of bounds with even the tiniest corners does not
576  // contain corners.
577  auto tiny_corners = RoundSuperellipse::MakeRectRadii(
578  bounds, RoundingRadii::MakeRadii({0.01f, 0.01f}));
579 
580  EXPECT_FALSE(tiny_corners.Contains({-50, -50}));
581  EXPECT_FALSE(tiny_corners.Contains({-50, 50}));
582  EXPECT_FALSE(tiny_corners.Contains({50, -50}));
583  EXPECT_FALSE(tiny_corners.Contains({50, 50}));
584 }
585 
586 TEST(RoundSuperellipseTest, UniformSquareContains) {
587  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
589  bounds, RoundingRadii::MakeRadii({5.0f, 5.0f}));
590 
591 #define CHECK_POINT_AND_MIRRORS(p) \
592  CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, 0.02)); \
593  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(1, -1), Point(0.02, -0.02)); \
594  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, 1), Point(-0.02, 0.02)); \
595  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, -0.02));
596 
597  CHECK_POINT_AND_MIRRORS(Point(0, 49.995)); // Top
598  CHECK_POINT_AND_MIRRORS(Point(44.245, 49.95)); // Top curve start
599  CHECK_POINT_AND_MIRRORS(Point(45.72, 49.87)); // Top joint
600  CHECK_POINT_AND_MIRRORS(Point(48.53, 48.53)); // Circular arc mid
601  CHECK_POINT_AND_MIRRORS(Point(49.87, 45.72)); // Right joint
602  CHECK_POINT_AND_MIRRORS(Point(49.95, 44.245)); // Right curve start
603  CHECK_POINT_AND_MIRRORS(Point(49.995, 0)); // Right
604 #undef CHECK_POINT_AND_MIRRORS
605 }
606 
607 TEST(RoundSuperellipseTest, UniformEllipticalContains) {
608  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
610  bounds, RoundingRadii::MakeRadii({5.0f, 10.0f}));
611 
612 #define CHECK_POINT_AND_MIRRORS(p) \
613  CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, 0.02)); \
614  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(1, -1), Point(0.02, -0.02)); \
615  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, 1), Point(-0.02, 0.02)); \
616  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, -0.02));
617 
618  CHECK_POINT_AND_MIRRORS(Point(0, 49.995)); // Top
619  CHECK_POINT_AND_MIRRORS(Point(44.245, 49.911)); // Top curve start
620  CHECK_POINT_AND_MIRRORS(Point(45.72, 49.75)); // Top joint
621  CHECK_POINT_AND_MIRRORS(Point(48.51, 47.07)); // Circular arc mid
622  CHECK_POINT_AND_MIRRORS(Point(49.87, 41.44)); // Right joint
623  CHECK_POINT_AND_MIRRORS(Point(49.95, 38.49)); // Right curve start
624  CHECK_POINT_AND_MIRRORS(Point(49.995, 0)); // Right
625 #undef CHECK_POINT_AND_MIRRORS
626 }
627 
628 TEST(RoundSuperellipseTest, UniformRectangularContains) {
629  // The bounds is not centered at the origin and has unequal height and width.
630  Rect bounds = Rect::MakeLTRB(0.0f, 0.0f, 50.0f, 100.0f);
632  bounds, RoundingRadii::MakeRadii({23.0f, 30.0f}));
633 
634  Point center = bounds.GetCenter();
635 #define CHECK_POINT_AND_MIRRORS(p) \
636  CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(1, 1) + center, \
637  Point(0.02, 0.02)); \
638  CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(1, -1) + center, \
639  Point(0.02, -0.02)); \
640  CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(-1, 1) + center, \
641  Point(-0.02, 0.02)); \
642  CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(-1, -1) + center, \
643  Point(-0.02, -0.02));
644 
645  CHECK_POINT_AND_MIRRORS(Point(24.99, 99.99)); // Bottom mid edge
646  CHECK_POINT_AND_MIRRORS(Point(29.99, 99.64));
647  CHECK_POINT_AND_MIRRORS(Point(34.99, 98.06));
648  CHECK_POINT_AND_MIRRORS(Point(39.99, 94.73));
649  CHECK_POINT_AND_MIRRORS(Point(44.13, 89.99));
650  CHECK_POINT_AND_MIRRORS(Point(48.46, 79.99));
651  CHECK_POINT_AND_MIRRORS(Point(49.70, 69.99));
652  CHECK_POINT_AND_MIRRORS(Point(49.97, 59.99));
653  CHECK_POINT_AND_MIRRORS(Point(49.99, 49.99)); // Right mid edge
654 
655 #undef CHECK_POINT_AND_MIRRORS
656 }
657 
658 TEST(RoundSuperellipseTest, SlimDiagnalContains) {
659  // This shape has large radii on one diagnal and tiny radii on the other,
660  // resulting in a almond-like shape placed diagnally (NW to SE).
661  Rect bounds = Rect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
663  bounds, {
664  .top_left = Size(1.0, 1.0),
665  .top_right = Size(99.0, 99.0),
666  .bottom_left = Size(99.0, 99.0),
667  .bottom_right = Size(1.0, 1.0),
668  });
669 
670  EXPECT_TRUE(rr.Contains(Point{0, 0}));
671  EXPECT_FALSE(rr.Contains(Point{-49.999, -49.999}));
672  EXPECT_FALSE(rr.Contains(Point{-49.999, 49.999}));
673  EXPECT_FALSE(rr.Contains(Point{49.999, 49.999}));
674  EXPECT_FALSE(rr.Contains(Point{49.999, -49.999}));
675 
676  // The pointy ends at the NE and SW corners
677  CHECK_POINT_WITH_OFFSET(rr, Point(-49.70, -49.70), Point(-0.02, -0.02));
678  CHECK_POINT_WITH_OFFSET(rr, Point(49.70, 49.70), Point(0.02, 0.02));
679 
680 // Checks two points symmetrical to the origin.
681 #define CHECK_DIAGNAL_POINTS(p) \
682  CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, -0.02)); \
683  CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, 0.02));
684 
685  // A few other points along the edge
686  CHECK_DIAGNAL_POINTS(Point(-40.0, -49.59));
687  CHECK_DIAGNAL_POINTS(Point(-20.0, -45.64));
688  CHECK_DIAGNAL_POINTS(Point(0.0, -37.01));
689  CHECK_DIAGNAL_POINTS(Point(20.0, -21.96));
690  CHECK_DIAGNAL_POINTS(Point(21.05, -20.92));
691  CHECK_DIAGNAL_POINTS(Point(40.0, 5.68));
692 #undef CHECK_POINT_AND_MIRRORS
693 }
694 
695 } // namespace testing
696 } // namespace impeller
TEST(AllocationSizeTest, CanCreateTypedAllocations)
TPoint< Scalar > Point
Definition: point.h:327
TSize< Scalar > Size
Definition: size.h:159
#define CHECK_DIAGNAL_POINTS(p)
#define CHECK_POINT_WITH_OFFSET(rr, p, outward_offset)
#define CHECK_POINT_AND_MIRRORS(p)
constexpr RoundSuperellipse Expand(Scalar left, Scalar top, Scalar right, Scalar bottom) const
Returns a round rectangle with expanded edges. Negative expansion results in shrinking.
constexpr static RoundSuperellipse MakeOval(const Rect &rect)
constexpr const RoundingRadii & GetRadii() const
static RoundSuperellipse MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
constexpr bool IsOval() const
constexpr static RoundSuperellipse MakeRect(const Rect &rect)
constexpr bool IsFinite() const
constexpr bool IsEmpty() const
constexpr bool IsRect() const
constexpr RoundSuperellipse Shift(Scalar dx, Scalar dy) const
Returns a new round rectangle translated by the given offset.
constexpr static RoundSuperellipse MakeRectRadius(const Rect &rect, Scalar radius)
constexpr const Rect & GetBounds() const
constexpr static RoundSuperellipse MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
constexpr static RoundingRadii MakeRadii(Size radii)
constexpr auto GetBottom() const
Definition: rect.h:361
constexpr auto GetTop() const
Definition: rect.h:357
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:301
constexpr auto GetLeft() const
Definition: rect.h:355
constexpr auto GetRight() const
Definition: rect.h:359
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
Type height
Definition: size.h:29
Type width
Definition: size.h:28