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));
150 template <
typename U>
155 template <
typename Po
intIter>
157 const PointIter last) {
161 auto left = first->x;
163 auto right = first->x;
164 auto bottom = first->y;
165 for (
auto it = first + 1; it < last; ++it) {
166 left = std::min(left, it->x);
167 top = std::min(top, it->y);
168 right = std::max(right, it->x);
169 bottom = std::max(bottom, it->y);
176 std::numeric_limits<Type>::lowest(),
177 std::numeric_limits<Type>::max(),
178 std::numeric_limits<Type>::max());
182 return left_ == r.left_ &&
184 right_ == r.right_ &&
185 bottom_ == r.bottom_;
189 return !(*
this == r);
199 [[nodiscard]] constexpr
TRect Scale(Type scale_x, Type scale_y)
const {
200 return TRect(left_ * scale_x,
265 (o.
IsEmpty() || (o.left_ >= left_ &&
267 o.right_ <= right_ &&
268 o.bottom_ <= bottom_));
279 return std::isfinite(left_) &&
280 std::isfinite(top_) &&
281 std::isfinite(right_) &&
282 std::isfinite(bottom_);
287 [[nodiscard]] constexpr
bool IsEmpty()
const {
290 return !(left_ < right_ && top_ < bottom_);
301 return !
IsEmpty() && (right_ - left_) == (bottom_ - top_);
311 return {left_, top_};
323 [[nodiscard]] constexpr Type
GetX()
const {
return left_; }
327 [[nodiscard]] constexpr Type
GetY()
const {
return top_; }
332 return saturated::Sub(right_, left_);
338 return saturated::Sub(bottom_, top_);
341 [[nodiscard]] constexpr
auto GetLeft()
const {
return left_; }
343 [[nodiscard]] constexpr
auto GetTop()
const {
return top_; }
345 [[nodiscard]] constexpr
auto GetRight()
const {
return right_; }
347 [[nodiscard]] constexpr
auto GetBottom()
const {
return bottom_; }
350 return {left_, top_};
354 return {right_, top_};
358 return {left_, bottom_};
362 return {right_, bottom_};
366 [[nodiscard]] constexpr T
Area()
const {
369 return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
374 return {saturated::AverageScalar(left_, right_),
375 saturated::AverageScalar(top_, bottom_)};
378 [[nodiscard]] constexpr std::array<T, 4>
GetLTRB()
const {
379 return {left_, top_, right_, bottom_};
384 [[nodiscard]] constexpr std::array<T, 4>
GetXYWH()
const {
394 std::min(left_, right_),
395 std::min(top_, bottom_),
396 std::max(left_, right_),
397 std::max(top_, bottom_),
405 [[nodiscard]] constexpr std::array<TPoint<T>, 4>
GetPoints()
const {
420 for (
size_t i = 0; i < points.size(); i++) {
439 auto ul =
transform.TransformHomogenous({left_, top_});
440 auto ur =
transform.TransformHomogenous({right_, top_});
441 auto ll =
transform.TransformHomogenous({left_, bottom_});
442 auto lr =
transform.TransformHomogenous({right_, bottom_});
452 index = ClipAndInsert(points, index, ll, ul, ur);
453 index = ClipAndInsert(points, index, ul, ur, lr);
454 index = ClipAndInsert(points, index, ur, lr, ll);
455 index = ClipAndInsert(points, index, lr, ll, ul);
458 return bounds.value_or(
TRect{});
469 if (bounds.has_value()) {
470 return bounds.value();
490 if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
492 return Matrix( sx, 0.0f, 0.0f, 0.0f,
493 0.0f, sy, 0.0f, 0.0f,
494 0.0f, 0.0f, 1.0f, 0.0f,
512 std::min(left_, o.left_),
513 std::min(top_, o.top_),
514 std::max(right_, o.right_),
515 std::max(bottom_, o.bottom_),
520 const TRect& o)
const {
523 std::max(left_, o.left_),
524 std::max(top_, o.top_),
525 std::min(right_, o.right_),
526 std::min(bottom_, o.bottom_),
544 [[nodiscard]] constexpr std::optional<TRect<T>>
Cutout(
const TRect& o)
const {
554 const auto& [a_left, a_top, a_right, a_bottom] =
GetLTRB();
555 const auto& [b_left, b_top, b_right, b_bottom] = o.
GetLTRB();
556 if (b_left <= a_left && b_right >= a_right) {
557 if (b_top <= a_top && b_bottom >= a_bottom) {
561 if (b_top <= a_top && b_bottom > a_top) {
565 if (b_bottom >= a_bottom && b_top < a_bottom) {
570 if (b_top <= a_top && b_bottom >= a_bottom) {
571 if (b_left <= a_left && b_right > a_left) {
575 if (b_right >= a_right && b_left < a_right) {
591 saturated::Add(left_, dx),
592 saturated::Add(top_, dy),
593 saturated::Add(right_, dx),
594 saturated::Add(bottom_, dy),
610 saturated::Sub(left_, left),
611 saturated::Sub(top_, top),
612 saturated::Add(right_, right),
613 saturated::Add(bottom_, bottom),
621 saturated::Sub(left_, amount),
622 saturated::Sub(top_, amount),
623 saturated::Add(right_, amount),
624 saturated::Add(bottom_, amount),
631 T vertical_amount)
const {
633 saturated::Sub(left_, horizontal_amount),
634 saturated::Sub(top_, vertical_amount),
635 saturated::Add(right_, horizontal_amount),
636 saturated::Add(bottom_, vertical_amount),
660 return source.
Shift(-left_, -top_)
668 saturated::Cast<U, Type>(floor(r.GetTop())),
669 saturated::Cast<U, Type>(ceil(r.GetRight())),
670 saturated::Cast<U, Type>(ceil(r.GetBottom())));
676 saturated::Cast<U, Type>(round(r.GetTop())),
677 saturated::Cast<U, Type>(round(r.GetRight())),
678 saturated::Cast<U, Type>(round(r.GetBottom())));
681 [[nodiscard]] constexpr
static std::optional<TRect>
Union(
683 const std::optional<TRect>
b) {
684 return b.has_value() ? a.
Union(
b.value()) : a;
687 [[nodiscard]] constexpr
static std::optional<TRect>
Union(
688 const std::optional<TRect> a,
690 return a.has_value() ? a->Union(
b) :
b;
693 [[nodiscard]] constexpr
static std::optional<TRect>
Union(
694 const std::optional<TRect> a,
695 const std::optional<TRect>
b) {
696 return a.has_value() ?
Union(a.value(),
b) :
b;
701 const std::optional<TRect>
b) {
706 const std::optional<TRect> a,
708 return a.has_value() ? a->Intersection(
b) :
b;
712 const std::optional<TRect> a,
713 const std::optional<TRect>
b) {
718 constexpr
TRect(Type left, Type top, Type right, Type bottom)
719 : left_(left), top_(top), right_(right), bottom_(bottom) {}
726 static constexpr
Scalar kMinimumHomogenous = 1.0f / (1 << 14);
737 static constexpr
int ClipAndInsert(
Point clipped[],
741 const Vector3& right) {
742 if (p.z >= kMinimumHomogenous) {
743 clipped[index++] = {p.x / p.z, p.y / p.z};
745 index = InterpolateAndInsert(clipped, index, p, left);
746 index = InterpolateAndInsert(clipped, index, p, right);
754 static constexpr
int InterpolateAndInsert(
Point clipped[],
757 const Vector3& neighbor) {
758 if (neighbor.z >= kMinimumHomogenous) {
759 auto t = (kMinimumHomogenous - p.z) / (neighbor.z - p.z);
761 (t * p.x + (1.0f - t) * neighbor.x) / kMinimumHomogenous,
762 (t * p.y + (1.0f - t) * neighbor.y) / kMinimumHomogenous,
775 #undef ONLY_ON_FLOAT_M
790 #endif // FLUTTER_IMPELLER_GEOMETRY_RECT_H_