Skip to content

Commit 8e90d38

Browse files
chinmaygardednfield
authored andcommitted
Rect union and intersection.
1 parent 4234b34 commit 8e90d38

File tree

4 files changed

+123
-61
lines changed

4 files changed

+123
-61
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,24 @@ TEST_F(AiksTest, CanRenderClips) {
106106
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
107107
}
108108

109+
TEST_F(AiksTest, CanSaveLayerStandalone) {
110+
Canvas canvas;
111+
112+
Paint red;
113+
red.color = Color::Red();
114+
115+
Paint alpha;
116+
alpha.color = Color::Red().WithAlpha(0.5);
117+
118+
canvas.SaveLayer(alpha);
119+
120+
canvas.DrawCircle({125, 125}, 125, red);
121+
122+
canvas.Restore();
123+
124+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
125+
}
126+
109127
TEST_F(AiksTest, CanRenderGroupOpacity) {
110128
Canvas canvas;
111129

impeller/geometry/geometry_unittests.cc

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -141,38 +141,6 @@ TEST(GeometryTest, QuaternionLerp) {
141141
ASSERT_QUATERNION_NEAR(q3, expected);
142142
}
143143

144-
TEST(GeometryTest, RectWithPoint) {
145-
auto rect = Rect{};
146-
147-
auto expected = Rect{};
148-
149-
ASSERT_RECT_NEAR(rect, expected);
150-
151-
rect = rect.WithPoint({100, 100});
152-
expected = Rect{0, 0, 100, 100};
153-
ASSERT_RECT_NEAR(rect, expected);
154-
155-
rect = rect.WithPoint({-11, -12});
156-
expected = Rect{-11, -12, 111, 112};
157-
ASSERT_RECT_NEAR(rect, expected);
158-
159-
rect = rect.WithPoint({55, 65});
160-
expected = Rect{-11, -12, 111, 112};
161-
ASSERT_RECT_NEAR(rect, expected);
162-
163-
rect = rect.WithPoint({-25, 0});
164-
expected = Rect{-25, -12, 125, 112};
165-
ASSERT_RECT_NEAR(rect, expected);
166-
167-
rect = rect.WithPoint({0, -25});
168-
expected = Rect{-25, -25, 125, 125};
169-
ASSERT_RECT_NEAR(rect, expected);
170-
171-
rect = rect.WithPoint({125, 135});
172-
expected = Rect{-25, -25, 150, 160};
173-
ASSERT_RECT_NEAR(rect, expected);
174-
}
175-
176144
TEST(GeometryTest, SimplePath) {
177145
Path path;
178146

@@ -216,7 +184,7 @@ TEST(GeometryTest, BoundingBoxCubic) {
216184
Path path;
217185
path.AddCubicComponent({120, 160}, {25, 200}, {220, 260}, {220, 40});
218186
auto box = path.GetBoundingBox();
219-
Rect expected(0, 0, 220, 198.862);
187+
Rect expected(93.9101, 40, 126.09, 158.862);
220188
ASSERT_RECT_NEAR(box, expected);
221189
}
222190

@@ -225,7 +193,7 @@ TEST(GeometryTest, BoundingBoxOfCompositePathIsCorrect) {
225193
builder.AddRoundedRect({{10, 10}, {300, 300}}, {50, 50, 50, 50});
226194
auto path = builder.CreatePath();
227195
auto actual = path.GetBoundingBox();
228-
Rect expected(0, 0, 310, 310);
196+
Rect expected(10, 10, 300, 300);
229197
ASSERT_RECT_NEAR(actual, expected);
230198
}
231199

@@ -273,5 +241,72 @@ TEST(GeometryTest, CanConvertBetweenDegressAndRadians) {
273241
}
274242
}
275243

244+
TEST(GeometryTest, RectUnion) {
245+
{
246+
Rect a(100, 100, 100, 100);
247+
Rect b(0, 0, 0, 0);
248+
auto u = a.Union(b);
249+
auto expected = Rect(0, 0, 200, 200);
250+
ASSERT_RECT_NEAR(u, expected);
251+
}
252+
253+
{
254+
Rect a(100, 100, 100, 100);
255+
Rect b(10, 10, 0, 0);
256+
auto u = a.Union(b);
257+
auto expected = Rect(10, 10, 190, 190);
258+
ASSERT_RECT_NEAR(u, expected);
259+
}
260+
261+
{
262+
Rect a(0, 0, 100, 100);
263+
Rect b(10, 10, 100, 100);
264+
auto u = a.Union(b);
265+
auto expected = Rect(0, 0, 110, 110);
266+
ASSERT_RECT_NEAR(u, expected);
267+
}
268+
269+
{
270+
Rect a(0, 0, 100, 100);
271+
Rect b(100, 100, 100, 100);
272+
auto u = a.Union(b);
273+
auto expected = Rect(0, 0, 200, 200);
274+
ASSERT_RECT_NEAR(u, expected);
275+
}
276+
}
277+
278+
TEST(GeometryTest, RectIntersection) {
279+
{
280+
Rect a(100, 100, 100, 100);
281+
Rect b(0, 0, 0, 0);
282+
283+
auto u = a.Intersection(b);
284+
ASSERT_FALSE(u.has_value());
285+
}
286+
287+
{
288+
Rect a(100, 100, 100, 100);
289+
Rect b(10, 10, 0, 0);
290+
auto u = a.Intersection(b);
291+
ASSERT_FALSE(u.has_value());
292+
}
293+
294+
{
295+
Rect a(0, 0, 100, 100);
296+
Rect b(10, 10, 100, 100);
297+
auto u = a.Intersection(b);
298+
ASSERT_TRUE(u.has_value());
299+
auto expected = Rect(10, 10, 90, 90);
300+
ASSERT_RECT_NEAR(u.value(), expected);
301+
}
302+
303+
{
304+
Rect a(0, 0, 100, 100);
305+
Rect b(100, 100, 100, 100);
306+
auto u = a.Intersection(b);
307+
ASSERT_FALSE(u.has_value());
308+
}
309+
}
310+
276311
} // namespace testing
277312
} // namespace impeller

impeller/geometry/rect.h

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#pragma once
66

7+
#include <optional>
78
#include <ostream>
89
#include <vector>
910

@@ -87,35 +88,41 @@ struct TRect {
8788

8889
constexpr bool IsEmpty() const { return size.IsEmpty(); }
8990

90-
constexpr TRect WithPoint(const TPoint<Type>& p) const {
91-
TRect copy = *this;
92-
if (p.x < origin.x) {
93-
copy.origin.x = p.x;
94-
copy.size.width += (origin.x - p.x);
95-
}
96-
97-
if (p.y < origin.y) {
98-
copy.origin.y = p.y;
99-
copy.size.height += (origin.y - p.y);
100-
}
91+
constexpr std::array<T, 4> GetLTRB() const {
92+
const auto left = std::min(origin.x, origin.x + size.width);
93+
const auto top = std::min(origin.y, origin.y + size.height);
94+
const auto right = std::max(origin.x, origin.x + size.width);
95+
const auto bottom = std::max(origin.y, origin.y + size.height);
96+
return {left, top, right, bottom};
97+
}
10198

102-
if (p.x > (size.width + origin.x)) {
103-
copy.size.width += p.x - (size.width + origin.x);
104-
}
99+
constexpr TRect Union(const TRect& o) const {
100+
auto this_ltrb = GetLTRB();
101+
auto other_ltrb = o.GetLTRB();
102+
return TRect::MakeLTRB(std::min(this_ltrb[0], other_ltrb[0]), //
103+
std::min(this_ltrb[1], other_ltrb[1]), //
104+
std::max(this_ltrb[2], other_ltrb[2]), //
105+
std::max(this_ltrb[3], other_ltrb[3]) //
106+
);
107+
}
105108

106-
if (p.y > (size.height + origin.y)) {
107-
copy.size.height += p.y - (size.height + origin.y);
109+
constexpr std::optional<TRect<T>> Intersection(const TRect& o) const {
110+
auto this_ltrb = GetLTRB();
111+
auto other_ltrb = o.GetLTRB();
112+
auto intersection =
113+
TRect::MakeLTRB(std::max(this_ltrb[0], other_ltrb[0]), //
114+
std::max(this_ltrb[1], other_ltrb[1]), //
115+
std::min(this_ltrb[2], other_ltrb[2]), //
116+
std::min(this_ltrb[3], other_ltrb[3]) //
117+
);
118+
if (intersection.size.IsEmpty()) {
119+
return std::nullopt;
108120
}
109-
110-
return copy;
121+
return intersection;
111122
}
112123

113-
constexpr TRect WithPoints(const std::vector<TPoint<Type>>& points) const {
114-
TRect box = *this;
115-
for (const auto& point : points) {
116-
box = box.WithPoint(point);
117-
}
118-
return box;
124+
constexpr bool IntersectsWithRect(const TRect& o) const {
125+
return Interesection(o).has_value();
119126
}
120127
};
121128

impeller/geometry/size.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ struct TSize {
7979

8080
constexpr Type Area() const { return width * height; }
8181

82-
constexpr bool IsZero() const { return width * height == 0.0; }
82+
constexpr bool IsPositive() const { return width > 0 && height > 0; }
8383

84-
constexpr bool IsPositive() const { return width * height > 0.0; }
84+
constexpr bool IsNegative() const { return width < 0 || height < 0; }
8585

86-
constexpr bool IsEmpty() const { return !IsPositive(); }
86+
constexpr bool IsZero() const { return width == 0 || height == 0; }
87+
88+
constexpr bool IsEmpty() const { return IsNegative() || IsZero(); }
8789

8890
template <class U>
8991
static constexpr TSize Ceil(const TSize<U>& other) {

0 commit comments

Comments
 (0)