5 #ifndef FLUTTER_IMPELLER_GEOMETRY_RECT_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_RECT_H_
13 #include "fml/logging.h"
22 #define ONLY_ON_FLOAT_M(Modifiers, Return) \
23 template <typename U = T> \
24 Modifiers std::enable_if_t<std::is_floating_point_v<U>, Return>
25 #define ONLY_ON_FLOAT(Return) DL_ONLY_ON_FLOAT_M(, Return)
127 constexpr
TRect() : left_(0), top_(0), right_(0), bottom_(0) {}
133 return TRect(left, top, right, bottom);
137 return TRect(x, y, saturated::Add(x, width), saturated::Add(y, height));
141 return TRect(0, 0, width, height);
154 template <
typename U>
159 template <
typename Po
intIter>
161 const PointIter last) {
165 auto left = first->x;
167 auto right = first->x;
168 auto bottom = first->y;
169 for (
auto it = first + 1; it < last; ++it) {
170 left = std::min(left, it->x);
171 top = std::min(top, it->y);
172 right = std::max(right, it->x);
173 bottom = std::max(bottom, it->y);
180 std::numeric_limits<Type>::lowest(),
181 std::numeric_limits<Type>::max(),
182 std::numeric_limits<Type>::max());
186 return left_ == r.left_ &&
188 right_ == r.right_ &&
189 bottom_ == r.bottom_;
193 return !(*
this == r);
203 [[nodiscard]] constexpr
TRect Scale(Type scale_x, Type scale_y)
const {
204 return TRect(left_ * scale_x,
269 (o.
IsEmpty() || (o.left_ >= left_ &&
271 o.right_ <= right_ &&
272 o.bottom_ <= bottom_));
283 return std::isfinite(left_) &&
284 std::isfinite(top_) &&
285 std::isfinite(right_) &&
286 std::isfinite(bottom_);
291 [[nodiscard]] constexpr
bool IsEmpty()
const {
294 return !(left_ < right_ && top_ < bottom_);
305 return !
IsEmpty() && (right_ - left_) == (bottom_ - top_);
315 return {left_, top_};
327 [[nodiscard]] constexpr Type
GetX()
const {
return left_; }
331 [[nodiscard]] constexpr Type
GetY()
const {
return top_; }
336 return saturated::Sub(right_, left_);
342 return saturated::Sub(bottom_, top_);
345 [[nodiscard]] constexpr
auto GetLeft()
const {
return left_; }
347 [[nodiscard]] constexpr
auto GetTop()
const {
return top_; }
349 [[nodiscard]] constexpr
auto GetRight()
const {
return right_; }
351 [[nodiscard]] constexpr
auto GetBottom()
const {
return bottom_; }
354 return {left_, top_};
358 return {right_, top_};
362 return {left_, bottom_};
366 return {right_, bottom_};
370 [[nodiscard]] constexpr T
Area()
const {
372 return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
377 return {saturated::AverageScalar(left_, right_),
378 saturated::AverageScalar(top_, bottom_)};
381 [[nodiscard]] constexpr std::array<T, 4>
GetLTRB()
const {
382 return {left_, top_, right_, bottom_};
387 [[nodiscard]] constexpr std::array<T, 4>
GetXYWH()
const {
397 std::min(left_, right_),
398 std::min(top_, bottom_),
399 std::max(left_, right_),
400 std::max(top_, bottom_),
408 [[nodiscard]] constexpr std::array<TPoint<T>, 4>
GetPoints()
const {
423 for (
size_t i = 0; i < points.size(); i++) {
442 auto ul =
transform.TransformHomogenous({left_, top_});
443 auto ur =
transform.TransformHomogenous({right_, top_});
444 auto ll =
transform.TransformHomogenous({left_, bottom_});
445 auto lr =
transform.TransformHomogenous({right_, bottom_});
455 index = ClipAndInsert(points, index, ll, ul, ur);
456 index = ClipAndInsert(points, index, ul, ur, lr);
457 index = ClipAndInsert(points, index, ur, lr, ll);
458 index = ClipAndInsert(points, index, lr, ll, ul);
461 return bounds.value_or(
TRect{});
472 if (bounds.has_value()) {
473 return bounds.value();
493 if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
495 return Matrix( sx, 0.0f, 0.0f, 0.0f,
496 0.0f, sy, 0.0f, 0.0f,
497 0.0f, 0.0f, 1.0f, 0.0f,
515 std::min(left_, o.left_),
516 std::min(top_, o.top_),
517 std::max(right_, o.right_),
518 std::max(bottom_, o.bottom_),
523 const TRect& o)
const {
526 std::max(left_, o.left_),
527 std::max(top_, o.top_),
528 std::min(right_, o.right_),
529 std::min(bottom_, o.bottom_),
551 [[nodiscard]] constexpr std::optional<TRect<T>>
Cutout(
const TRect& o)
const {
561 const auto& [a_left, a_top, a_right, a_bottom] =
GetLTRB();
562 const auto& [b_left, b_top, b_right, b_bottom] = o.
GetLTRB();
563 if (b_left <= a_left && b_right >= a_right) {
564 if (b_top <= a_top && b_bottom >= a_bottom) {
568 if (b_top <= a_top && b_bottom > a_top) {
572 if (b_bottom >= a_bottom && b_top < a_bottom) {
577 if (b_top <= a_top && b_bottom >= a_bottom) {
578 if (b_left <= a_left && b_right > a_left) {
582 if (b_right >= a_right && b_left < a_right) {
598 saturated::Add(left_, dx),
599 saturated::Add(top_, dy),
600 saturated::Add(right_, dx),
601 saturated::Add(bottom_, dy),
617 saturated::Sub(left_, left),
618 saturated::Sub(top_, top),
619 saturated::Add(right_, right),
620 saturated::Add(bottom_, bottom),
628 saturated::Sub(left_, amount),
629 saturated::Sub(top_, amount),
630 saturated::Add(right_, amount),
631 saturated::Add(bottom_, amount),
638 T vertical_amount)
const {
640 saturated::Sub(left_, horizontal_amount),
641 saturated::Sub(top_, vertical_amount),
642 saturated::Add(right_, horizontal_amount),
643 saturated::Add(bottom_, vertical_amount),
667 return source.
Shift(-left_, -top_)
675 saturated::Cast<U, Type>(floor(r.GetTop())),
676 saturated::Cast<U, Type>(ceil(r.GetRight())),
677 saturated::Cast<U, Type>(ceil(r.GetBottom())));
683 saturated::Cast<U, Type>(round(r.GetTop())),
684 saturated::Cast<U, Type>(round(r.GetRight())),
685 saturated::Cast<U, Type>(round(r.GetBottom())));
688 [[nodiscard]] constexpr
static std::optional<TRect>
Union(
690 const std::optional<TRect>
b) {
691 return b.has_value() ? a.
Union(
b.value()) : a;
694 [[nodiscard]] constexpr
static std::optional<TRect>
Union(
695 const std::optional<TRect> a,
697 return a.has_value() ? a->Union(
b) :
b;
700 [[nodiscard]] constexpr
static std::optional<TRect>
Union(
701 const std::optional<TRect> a,
702 const std::optional<TRect>
b) {
703 return a.has_value() ?
Union(a.value(),
b) :
b;
708 const std::optional<TRect>
b) {
713 const std::optional<TRect> a,
715 return a.has_value() ? a->Intersection(
b) :
b;
719 const std::optional<TRect> a,
720 const std::optional<TRect>
b) {
725 constexpr
TRect(Type left, Type top, Type right, Type bottom)
726 : left_(left), top_(top), right_(right), bottom_(bottom) {}
733 static constexpr
Scalar kMinimumHomogenous = 1.0f / (1 << 14);
744 static constexpr
int ClipAndInsert(
Point clipped[],
748 const Vector3& right) {
749 if (p.z >= kMinimumHomogenous) {
750 clipped[index++] = {p.x / p.z, p.y / p.z};
752 index = InterpolateAndInsert(clipped, index, p, left);
753 index = InterpolateAndInsert(clipped, index, p, right);
761 static constexpr
int InterpolateAndInsert(
Point clipped[],
764 const Vector3& neighbor) {
765 if (neighbor.z >= kMinimumHomogenous) {
766 auto t = (kMinimumHomogenous - p.z) / (neighbor.z - p.z);
768 (t * p.x + (1.0f - t) * neighbor.x) / kMinimumHomogenous,
769 (t * p.y + (1.0f - t) * neighbor.y) / kMinimumHomogenous,
782 #undef ONLY_ON_FLOAT_M
797 #endif // FLUTTER_IMPELLER_GEOMETRY_RECT_H_