40 if (
empty() || other.empty())
return false;
41 return x < other.right() &&
right() > other.x &&
42 y < other.bottom() &&
bottom() > other.y;
46 float ix = std::max(
x, other.x);
47 float iy = std::max(
y, other.y);
48 float ir = std::min(
right(), other.right());
49 float ib = std::min(
bottom(), other.bottom());
50 if (ir <= ix || ib <= iy)
return {};
51 return {ix, iy, ir - ix, ib - iy};
55 if (
empty())
return other;
56 if (other.empty())
return *
this;
57 float ux = std::min(
x, other.x);
58 float uy = std::min(
y, other.y);
59 float ur = std::max(
right(), other.right());
60 float ub = std::max(
bottom(), other.bottom());
61 return {ux, uy, ur - ux, ub - uy};
65 return x == o.x &&
y == o.y &&
width == o.width &&
height == o.height;
77 rects_.push_back(rect);
81 void clear() { rects_.clear(); }
84 bool empty()
const {
return rects_.empty(); }
87 int size()
const {
return static_cast<int>(rects_.size()); }
94 for (
auto& r : rects_)
95 if (r.contains(px, py))
return true;
101 for (
auto& r : rects_)
102 if (r.intersects(rect))
return true;
108 if (rects_.empty())
return {};
109 Rect2D result = rects_[0];
110 for (
size_t i = 1; i < rects_.size(); ++i)
118 for (
auto& r : rects_)
119 area += r.width * r.height;
126 for (
auto& r : rects_) {
127 auto i = r.intersection(clip);
136 std::vector<Rect2D> result;
137 for (
auto& r : rects_) {
138 if (!r.intersects(sub)) {
145 result.push_back({r.x, r.y, r.width, sub.
y - r.y});
147 if (sub.
bottom() < r.bottom())
148 result.push_back({r.x, sub.
bottom(), r.width, r.bottom() - sub.
bottom()});
150 float mid_top = std::max(r.y, sub.
y);
151 float mid_bot = std::min(r.bottom(), sub.
bottom());
153 result.push_back({r.x, mid_top, sub.
x - r.x, mid_bot - mid_top});
155 if (sub.
right() < r.right())
156 result.push_back({sub.
right(), mid_top, r.right() - sub.
right(), mid_bot - mid_top});
158 rects_ = std::move(result);
162 auto begin()
const {
return rects_.begin(); }
163 auto end()
const {
return rects_.end(); }
187 if (rect.
empty())
return;
188 rects_.push_back(rect);
197 if (sub.
empty())
return;
198 std::vector<Rect2D> out;
199 out.reserve(rects_.size());
200 for (
auto& r : rects_) {
201 if (!r.intersects(sub)) {
206 if (sub.
y > r.y + aa_tolerance) {
207 out.push_back({r.x, r.y, r.width, sub.
y - r.y});
210 if (sub.
bottom() + aa_tolerance < r.bottom()) {
211 out.push_back({r.x, sub.
bottom(), r.width, r.bottom() - sub.
bottom()});
213 float mid_top = std::max(r.y, sub.
y);
214 float mid_bot = std::min(r.bottom(), sub.
bottom());
215 float mid_h = mid_bot - mid_top;
216 if (mid_h > aa_tolerance) {
218 if (sub.
x > r.x + aa_tolerance) {
219 out.push_back({r.x, mid_top, sub.
x - r.x, mid_h});
222 if (sub.
right() + aa_tolerance < r.right()) {
223 out.push_back({sub.
right(), mid_top, r.right() - sub.
right(), mid_h});
227 rects_ = std::move(out);
234 std::vector<Rect2D> out;
235 out.reserve(rects_.size());
236 for (
auto& r : rects_) {
237 auto i = r.intersection(clip);
240 if (i.empty())
continue;
241 if (i.width < aa_tolerance || i.height < aa_tolerance)
continue;
244 rects_ = std::move(out);
253 while (merged && rects_.size() >= 2) {
255 for (std::size_t i = 0; i < rects_.size() && !merged; ++i) {
256 for (std::size_t j = i + 1; j < rects_.size(); ++j) {
262 std::abs(a.y - b.y) < aa_tolerance &&
263 std::abs(a.height - b.height) < aa_tolerance;
265 if (std::abs(a.right() - b.x) < aa_tolerance) {
266 a = {a.x, a.y, a.width + b.width, a.height};
267 rects_.erase(rects_.begin() +
static_cast<long>(j));
271 if (std::abs(b.right() - a.x) < aa_tolerance) {
272 a = {b.x, a.y, a.width + b.width, a.height};
273 rects_.erase(rects_.begin() +
static_cast<long>(j));
280 std::abs(a.x - b.x) < aa_tolerance &&
281 std::abs(a.width - b.width) < aa_tolerance;
283 if (std::abs(a.bottom() - b.y) < aa_tolerance) {
284 a = {a.x, a.y, a.width, a.height + b.height};
285 rects_.erase(rects_.begin() +
static_cast<long>(j));
289 if (std::abs(b.bottom() - a.y) < aa_tolerance) {
290 a = {a.x, b.y, a.width, a.height + b.height};
291 rects_.erase(rects_.begin() +
static_cast<long>(j));
307#if defined(PULP_HAS_SKIA) && PULP_HAS_SKIA
315 std::vector<Rect2D> rects_;
void add(const Rect2D &rect)
Add a rectangle to the list (may overlap existing).
Definition rectangle_list.hpp:75
int size() const
Number of rectangles.
Definition rectangle_list.hpp:87
void coalesce_aa(float aa_tolerance=1.0f/256.0f)
Coalesce adjacent rectangles that share a full edge (within aa_tolerance).
Definition rectangle_list.hpp:251
bool empty() const
Whether the list is empty.
Definition rectangle_list.hpp:84
auto begin() const
Iterator support.
Definition rectangle_list.hpp:162
void intersect_aa(const Rect2D &clip, float aa_tolerance=1.0f/256.0f)
Antialiased intersect — keep only the intersection with clip, in-place.
Definition rectangle_list.hpp:233
void subtract_aa(const Rect2D &sub, float aa_tolerance=1.0f/256.0f)
Antialiased subtract — splits intersecting rectangles into non-overlapping pieces.
Definition rectangle_list.hpp:196
static constexpr const char * aa_backend()
Reports the implementation backend in use.
Definition rectangle_list.hpp:306
bool intersects(const Rect2D &rect) const
Whether any rectangle intersects the given rect.
Definition rectangle_list.hpp:100
Rect2D bounding_box() const
Compute the bounding box of all rectangles.
Definition rectangle_list.hpp:107
auto end() const
Definition rectangle_list.hpp:163
void clear()
Clear all rectangles.
Definition rectangle_list.hpp:81
void subtract(const Rect2D &sub)
Subtract a rectangle from all rectangles in the list.
Definition rectangle_list.hpp:135
void union_aa(const Rect2D &rect, float aa_tolerance=1.0f/256.0f)
Antialiased union — appends rect, then merges any pieces that share an edge to within aa_tolerance.
Definition rectangle_list.hpp:186
float total_area() const
Total area (may double-count overlapping regions).
Definition rectangle_list.hpp:116
RectangleList clipped(const Rect2D &clip) const
Clip this list against a rectangle (keep only the intersection).
Definition rectangle_list.hpp:124
const Rect2D & operator[](int i) const
Get a rectangle by index.
Definition rectangle_list.hpp:90
bool contains(float px, float py) const
Whether a point is contained in any rectangle.
Definition rectangle_list.hpp:93
Definition affine_transform.hpp:24
Axis-aligned rectangle in canvas coordinates.
Definition rectangle_list.hpp:28
float right() const
Definition rectangle_list.hpp:31
float y
Definition rectangle_list.hpp:29
bool intersects(const Rect2D &other) const
Definition rectangle_list.hpp:39
Rect2D enclosing_union(const Rect2D &other) const
Definition rectangle_list.hpp:54
float x
Definition rectangle_list.hpp:29
Rect2D intersection(const Rect2D &other) const
Definition rectangle_list.hpp:45
float height
Definition rectangle_list.hpp:29
float width
Definition rectangle_list.hpp:29
bool empty() const
Definition rectangle_list.hpp:33
bool contains(float px, float py) const
Definition rectangle_list.hpp:35
float bottom() const
Definition rectangle_list.hpp:32
bool operator==(const Rect2D &o) const
Definition rectangle_list.hpp:64