5 #include "gtest/gtest.h"
12 #define CHECK_POINT_WITH_OFFSET(rr, p, outward_offset) \
13 EXPECT_TRUE(rr.Contains(p)); \
14 EXPECT_FALSE(rr.Contains(p + outward_offset));
22 class SpyPathReceiver :
public PathReceiver {
25 using LineSegment = std::function<void(
const Point&)>;
29 using ConicSegment = std::function<void(
const Point&,
const Point&,
Scalar)>;
31 void SpyLineTo(LineSegment line_to) { line_to_ = std::move(line_to); }
33 void SpyCubicTo(CubicSegment cubic_to) { cubic_to_ = std::move(cubic_to); }
35 void SpyConicTo(ConicSegment conic_to) { conic_to_ = std::move(conic_to); }
46 void QuadTo(
const Point& cp,
const Point&
p2)
override {}
50 cubic_to_(cp1, cp2,
p2);
61 void Close()
override {}
65 CubicSegment cubic_to_;
66 ConicSegment conic_to_;
73 TEST(RoundSuperellipseTest, EmptyDeclaration) {
77 EXPECT_FALSE(rse.
IsRect());
78 EXPECT_FALSE(rse.
IsOval());
100 TEST(RoundSuperellipseTest, DefaultConstructor) {
104 EXPECT_FALSE(rse.
IsRect());
105 EXPECT_FALSE(rse.
IsOval());
115 TEST(RoundSuperellipseTest, EmptyRectConstruction) {
120 EXPECT_FALSE(rse.
IsRect());
121 EXPECT_FALSE(rse.
IsOval());
131 TEST(RoundSuperellipseTest, RectConstructor) {
136 EXPECT_TRUE(rse.
IsRect());
137 EXPECT_FALSE(rse.
IsOval());
147 TEST(RoundSuperellipseTest, InvertedRectConstruction) {
152 EXPECT_TRUE(rse.
IsRect());
153 EXPECT_FALSE(rse.
IsOval());
163 TEST(RoundSuperellipseTest, EmptyOvalConstruction) {
168 EXPECT_FALSE(rse.
IsRect());
169 EXPECT_FALSE(rse.
IsOval());
179 TEST(RoundSuperellipseTest, OvalConstructor) {
184 EXPECT_FALSE(rse.
IsRect());
185 EXPECT_TRUE(rse.
IsOval());
195 TEST(RoundSuperellipseTest, InvertedOvalConstruction) {
200 EXPECT_FALSE(rse.
IsRect());
201 EXPECT_TRUE(rse.
IsOval());
211 TEST(RoundSuperellipseTest, RectRadiusConstructor) {
216 EXPECT_FALSE(rse.
IsRect());
217 EXPECT_FALSE(rse.
IsOval());
227 TEST(RoundSuperellipseTest, RectXYConstructor) {
232 EXPECT_FALSE(rse.
IsRect());
233 EXPECT_FALSE(rse.
IsOval());
243 TEST(RoundSuperellipseTest, RectSizeConstructor) {
248 EXPECT_FALSE(rse.
IsRect());
249 EXPECT_FALSE(rse.
IsOval());
259 TEST(RoundSuperellipseTest, RectRadiiConstructor) {
263 .top_left =
Size(1.0, 1.5),
264 .top_right =
Size(2.0, 2.5f),
265 .bottom_left =
Size(3.0, 3.5f),
266 .bottom_right =
Size(4.0, 4.5f),
270 EXPECT_FALSE(rse.
IsRect());
271 EXPECT_FALSE(rse.
IsOval());
281 TEST(RoundSuperellipseTest, RectRadiiOverflowWidthConstructor) {
285 .top_left =
Size(1.0f, 2.0f),
286 .top_right =
Size(3.0f, 4.0f),
287 .bottom_left =
Size(5.0f, 6.0f),
288 .bottom_right =
Size(7.0f, 8.0f),
295 EXPECT_FALSE(rse.
IsRect());
296 EXPECT_FALSE(rse.
IsOval());
306 TEST(RoundSuperellipseTest, RectRadiiOverflowHeightConstructor) {
310 .top_left =
Size(1.0f, 2.0f),
311 .top_right =
Size(3.0f, 4.0f),
312 .bottom_left =
Size(5.0f, 6.0f),
313 .bottom_right =
Size(7.0f, 8.0f),
320 EXPECT_FALSE(rse.
IsRect());
321 EXPECT_FALSE(rse.
IsOval());
331 TEST(RoundSuperellipseTest, Shift) {
335 .top_left =
Size(1.0f, 2.0f),
336 .top_right =
Size(3.0f, 4.0f),
337 .bottom_left =
Size(5.0f, 6.0f),
338 .bottom_right =
Size(7.0f, 8.0f),
342 EXPECT_FALSE(shifted.IsEmpty());
343 EXPECT_FALSE(shifted.IsRect());
344 EXPECT_FALSE(shifted.IsOval());
345 EXPECT_TRUE(shifted.IsFinite());
346 EXPECT_FALSE(shifted.GetBounds().IsEmpty());
347 EXPECT_EQ(shifted.GetBounds(),
Rect::MakeLTRB(15.0f, 16.0f, 45.0f, 46.0f));
348 EXPECT_EQ(shifted.GetRadii().top_left,
Size(1.0f, 2.0f));
349 EXPECT_EQ(shifted.GetRadii().top_right,
Size(3.0f, 4.0f));
350 EXPECT_EQ(shifted.GetRadii().bottom_left,
Size(5.0f, 6.0f));
351 EXPECT_EQ(shifted.GetRadii().bottom_right,
Size(7.0f, 8.0f));
356 .top_left =
Size(1.0f, 2.0f),
357 .top_right =
Size(3.0f, 4.0f),
358 .bottom_left =
Size(5.0f, 6.0f),
359 .bottom_right =
Size(7.0f, 8.0f),
363 TEST(RoundSuperellipseTest, ExpandScalar) {
367 .top_left =
Size(1.0f, 2.0f),
368 .top_right =
Size(3.0f, 4.0f),
369 .bottom_left =
Size(5.0f, 6.0f),
370 .bottom_right =
Size(7.0f, 8.0f),
374 EXPECT_FALSE(expanded.IsEmpty());
375 EXPECT_FALSE(expanded.IsRect());
376 EXPECT_FALSE(expanded.IsOval());
377 EXPECT_TRUE(expanded.IsFinite());
378 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
379 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(5.0f, 5.0f, 45.0f, 45.0f));
380 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
381 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
382 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
383 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
388 .top_left =
Size(1.0f, 2.0f),
389 .top_right =
Size(3.0f, 4.0f),
390 .bottom_left =
Size(5.0f, 6.0f),
391 .bottom_right =
Size(7.0f, 8.0f),
395 TEST(RoundSuperellipseTest, ExpandTwoScalars) {
399 .top_left =
Size(1.0f, 2.0f),
400 .top_right =
Size(3.0f, 4.0f),
401 .bottom_left =
Size(5.0f, 6.0f),
402 .bottom_right =
Size(7.0f, 8.0f),
406 EXPECT_FALSE(expanded.IsEmpty());
407 EXPECT_FALSE(expanded.IsRect());
408 EXPECT_FALSE(expanded.IsOval());
409 EXPECT_TRUE(expanded.IsFinite());
410 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
411 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(5.0f, 4.0f, 45.0f, 46.0f));
412 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
413 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
414 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
415 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
420 .top_left =
Size(1.0f, 2.0f),
421 .top_right =
Size(3.0f, 4.0f),
422 .bottom_left =
Size(5.0f, 6.0f),
423 .bottom_right =
Size(7.0f, 8.0f),
427 TEST(RoundSuperellipseTest, ExpandFourScalars) {
431 .top_left =
Size(1.0f, 2.0f),
432 .top_right =
Size(3.0f, 4.0f),
433 .bottom_left =
Size(5.0f, 6.0f),
434 .bottom_right =
Size(7.0f, 8.0f),
438 EXPECT_FALSE(expanded.IsEmpty());
439 EXPECT_FALSE(expanded.IsRect());
440 EXPECT_FALSE(expanded.IsOval());
441 EXPECT_TRUE(expanded.IsFinite());
442 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
443 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(5.0f, 4.0f, 47.0f, 48.0f));
444 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
445 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
446 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
447 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
452 .top_left =
Size(1.0f, 2.0f),
453 .top_right =
Size(3.0f, 4.0f),
454 .bottom_left =
Size(5.0f, 6.0f),
455 .bottom_right =
Size(7.0f, 8.0f),
459 TEST(RoundSuperellipseTest, ContractScalar) {
463 .top_left =
Size(1.0f, 2.0f),
464 .top_right =
Size(3.0f, 4.0f),
465 .bottom_left =
Size(5.0f, 6.0f),
466 .bottom_right =
Size(7.0f, 8.0f),
470 EXPECT_FALSE(expanded.IsEmpty());
471 EXPECT_FALSE(expanded.IsRect());
472 EXPECT_FALSE(expanded.IsOval());
473 EXPECT_TRUE(expanded.IsFinite());
474 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
475 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(12.0f, 12.0f, 38.0f, 38.0f));
476 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
477 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
478 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
479 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
484 .top_left =
Size(1.0f, 2.0f),
485 .top_right =
Size(3.0f, 4.0f),
486 .bottom_left =
Size(5.0f, 6.0f),
487 .bottom_right =
Size(7.0f, 8.0f),
491 TEST(RoundSuperellipseTest, ContractTwoScalars) {
495 .top_left =
Size(1.0f, 2.0f),
496 .top_right =
Size(3.0f, 4.0f),
497 .bottom_left =
Size(5.0f, 6.0f),
498 .bottom_right =
Size(7.0f, 8.0f),
502 EXPECT_FALSE(expanded.IsEmpty());
503 EXPECT_FALSE(expanded.IsRect());
504 EXPECT_FALSE(expanded.IsOval());
505 EXPECT_TRUE(expanded.IsFinite());
506 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
507 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(11.0f, 12.0f, 39.0f, 38.0f));
508 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
509 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
510 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
511 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
516 .top_left =
Size(1.0f, 2.0f),
517 .top_right =
Size(3.0f, 4.0f),
518 .bottom_left =
Size(5.0f, 6.0f),
519 .bottom_right =
Size(7.0f, 8.0f),
523 TEST(RoundSuperellipseTest, ContractFourScalars) {
527 .top_left =
Size(1.0f, 2.0f),
528 .top_right =
Size(3.0f, 4.0f),
529 .bottom_left =
Size(5.0f, 6.0f),
530 .bottom_right =
Size(7.0f, 8.0f),
534 EXPECT_FALSE(expanded.IsEmpty());
535 EXPECT_FALSE(expanded.IsRect());
536 EXPECT_FALSE(expanded.IsOval());
537 EXPECT_TRUE(expanded.IsFinite());
538 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
539 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(11.0f, 11.5f, 38.0f, 37.5f));
540 EXPECT_EQ(expanded.GetRadii().top_left,
Size(1.0f, 2.0f));
541 EXPECT_EQ(expanded.GetRadii().top_right,
Size(3.0f, 4.0f));
542 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(5.0f, 6.0f));
543 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(7.0f, 8.0f));
548 .top_left =
Size(1.0f, 2.0f),
549 .top_right =
Size(3.0f, 4.0f),
550 .bottom_left =
Size(5.0f, 6.0f),
551 .bottom_right =
Size(7.0f, 8.0f),
555 TEST(RoundSuperellipseTest, ContractAndRequireRadiiAdjustment) {
559 .top_left =
Size(1.0f, 2.0f),
560 .top_right =
Size(3.0f, 4.0f),
561 .bottom_left =
Size(5.0f, 6.0f),
562 .bottom_right =
Size(7.0f, 8.0f),
570 EXPECT_FALSE(expanded.IsEmpty());
571 EXPECT_FALSE(expanded.IsRect());
572 EXPECT_FALSE(expanded.IsOval());
573 EXPECT_TRUE(expanded.IsFinite());
574 EXPECT_FALSE(expanded.GetBounds().IsEmpty());
575 EXPECT_EQ(expanded.GetBounds(),
Rect::MakeLTRB(22.0f, 22.0f, 28.0f, 28.0f));
576 EXPECT_EQ(expanded.GetRadii().top_left,
Size(0.5f, 1.0f));
577 EXPECT_EQ(expanded.GetRadii().top_right,
Size(1.5f, 2.0f));
578 EXPECT_EQ(expanded.GetRadii().bottom_left,
Size(2.5f, 3.0f));
579 EXPECT_EQ(expanded.GetRadii().bottom_right,
Size(3.5f, 4.0f));
586 .top_left =
Size(1.0f, 2.0f),
587 .top_right =
Size(3.0f, 4.0f),
588 .bottom_left =
Size(5.0f, 6.0f),
589 .bottom_right =
Size(7.0f, 8.0f),
598 .top_left =
Size(0.5f, 1.0f),
599 .top_right =
Size(1.5f, 2.0f),
600 .bottom_left =
Size(2.5f, 3.0f),
601 .bottom_right =
Size(3.5f, 4.0f),
605 TEST(RoundSuperellipseTest, NoCornerRoundSuperellipseContains) {
612 EXPECT_TRUE(no_corners.Contains({-50, -50}));
615 EXPECT_TRUE(no_corners.Contains({-50, 49.99}));
616 EXPECT_TRUE(no_corners.Contains({49.99, -50}));
617 EXPECT_TRUE(no_corners.Contains({49.99, 49.99}));
618 EXPECT_FALSE(no_corners.Contains({-50.01, -50}));
619 EXPECT_FALSE(no_corners.Contains({-50, -50.01}));
620 EXPECT_FALSE(no_corners.Contains({-50.01, 50}));
621 EXPECT_FALSE(no_corners.Contains({-50, 50.01}));
622 EXPECT_FALSE(no_corners.Contains({50.01, -50}));
623 EXPECT_FALSE(no_corners.Contains({50, -50.01}));
624 EXPECT_FALSE(no_corners.Contains({50.01, 50}));
625 EXPECT_FALSE(no_corners.Contains({50, 50.01}));
628 TEST(RoundSuperellipseTest, TinyCornerContains) {
635 EXPECT_FALSE(tiny_corners.Contains({-50, -50}));
636 EXPECT_FALSE(tiny_corners.Contains({-50, 50}));
637 EXPECT_FALSE(tiny_corners.Contains({50, -50}));
638 EXPECT_FALSE(tiny_corners.Contains({50, 50}));
641 TEST(RoundSuperellipseTest, UniformSquareContains) {
646 #define CHECK_POINT_AND_MIRRORS(p) \
647 CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, 0.02)); \
648 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(1, -1), Point(0.02, -0.02)); \
649 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, 1), Point(-0.02, 0.02)); \
650 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, -0.02));
659 #undef CHECK_POINT_AND_MIRRORS
662 TEST(RoundSuperellipseTest, UniformEllipticalContains) {
667 #define CHECK_POINT_AND_MIRRORS(p) \
668 CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, 0.02)); \
669 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(1, -1), Point(0.02, -0.02)); \
670 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, 1), Point(-0.02, 0.02)); \
671 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, -0.02));
680 #undef CHECK_POINT_AND_MIRRORS
683 TEST(RoundSuperellipseTest, UniformRectangularContains) {
690 #define CHECK_POINT_AND_MIRRORS(p) \
691 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(1, 1) + center, \
692 Point(0.02, 0.02)); \
693 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(1, -1) + center, \
694 Point(0.02, -0.02)); \
695 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(-1, 1) + center, \
696 Point(-0.02, 0.02)); \
697 CHECK_POINT_WITH_OFFSET(rr, (p - center) * Point(-1, -1) + center, \
698 Point(-0.02, -0.02));
710 #undef CHECK_POINT_AND_MIRRORS
713 TEST(RoundSuperellipseTest, SlimDiagonalContains) {
719 .top_left =
Size(1.0, 1.0),
720 .top_right =
Size(99.0, 99.0),
721 .bottom_left =
Size(99.0, 99.0),
722 .bottom_right =
Size(1.0, 1.0),
725 EXPECT_TRUE(rr.Contains(
Point{0, 0}));
726 EXPECT_FALSE(rr.Contains(
Point{-49.999, -49.999}));
727 EXPECT_FALSE(rr.Contains(
Point{-49.999, 49.999}));
728 EXPECT_FALSE(rr.Contains(
Point{49.999, 49.999}));
729 EXPECT_FALSE(rr.Contains(
Point{49.999, -49.999}));
736 #define CHECK_DIAGONAL_POINTS(p) \
737 CHECK_POINT_WITH_OFFSET(rr, (p), Point(0.02, -0.02)); \
738 CHECK_POINT_WITH_OFFSET(rr, (p) * Point(-1, -1), Point(-0.02, 0.02));
747 #undef CHECK_POINT_AND_MIRRORS
750 TEST(RoundSuperellipseTest, PointsOutsideOfSharpCorner) {
758 .top_left =
Size(0.0, 0.0),
759 .top_right =
Size(3.0, 3.0),
760 .bottom_left =
Size(0.0, 0.0),
761 .bottom_right =
Size(3.0, 3.0),
764 EXPECT_FALSE(rr.Contains(
Point{147.0, 14.0}));
768 PathForRectangularRseWithShapeCornersShouldBeWithinBounds) {
779 .top_left =
Size(14.0, 14.0),
780 .top_right =
Size(14.0, 14.0),
781 .bottom_left =
Size(0.0, 0.0),
782 .bottom_right =
Size(0.0, 0.0),
784 SpyPathReceiver receiver;
794 TEST(RoundSuperellipseTest, PathForLongRseShouldBeCorrect) {
799 SpyPathReceiver receiver;
812 rr.Dispatch(receiver);
TEST(AllocationSizeTest, CanCreateTypedAllocations)
void MoveTo(PathBuilder *builder, Scalar x, Scalar y)
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
void CubicTo(PathBuilder *builder, Scalar x1, Scalar y1, Scalar x2, Scalar y2, Scalar x3, Scalar y3)
void Close(PathBuilder *builder)
#define CHECK_DIAGONAL_POINTS(p)
#define CHECK_POINT_WITH_OFFSET(rr, p, outward_offset)
#define CHECK_POINT_AND_MIRRORS(p)
constexpr const RoundingRadii & GetRadii() const
static RoundSuperellipse MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
constexpr bool IsOval() const
constexpr bool IsFinite() const
constexpr bool IsEmpty() const
RoundSuperellipse Expand(Scalar left, Scalar top, Scalar right, Scalar bottom) const
Returns a round rectangle with expanded edges. Negative expansion results in shrinking.
constexpr bool IsRect() const
static RoundSuperellipse MakeOval(const Rect &rect)
RoundSuperellipse Shift(Scalar dx, Scalar dy) const
Returns a new round rectangle translated by the given offset.
static RoundSuperellipse MakeRect(const Rect &rect)
static RoundSuperellipse MakeRectRadius(const Rect &rect, Scalar radius)
constexpr const Rect & GetBounds() const
static RoundSuperellipse MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
void Dispatch(PathReceiver &receiver) const
static RoundSuperellipseParam MakeBoundsRadius(const Rect &bounds, Scalar radius)
constexpr static RoundingRadii MakeRadii(Size radii)
constexpr auto GetBottom() const
constexpr bool ContainsInclusive(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the closed-range interior of this rectangle.
constexpr auto GetTop() const
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr auto GetLeft() const
constexpr auto GetRight() const
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)