Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
rect.h File Reference
#include <array>
#include <optional>
#include <ostream>
#include <vector>
#include "fml/logging.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/saturated_math.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/size.h"

Go to the source code of this file.

Classes

struct  impeller::TRect< T >
 

Namespaces

namespace  impeller
 
namespace  std
 

Macros

#define ONLY_ON_FLOAT_M(Modifiers, Return)
 
#define ONLY_ON_FLOAT(Return)   DL_ONLY_ON_FLOAT_M(, Return)
 

Typedefs

using impeller::Rect = TRect< Scalar >
 
using impeller::IRect32 = TRect< int32_t >
 
using impeller::IRect64 = TRect< int64_t >
 
using impeller::IRect = IRect64
 

Macro Definition Documentation

◆ ONLY_ON_FLOAT

#define ONLY_ON_FLOAT (   Return)    DL_ONLY_ON_FLOAT_M(, Return)

Definition at line 25 of file rect.h.

◆ ONLY_ON_FLOAT_M

#define ONLY_ON_FLOAT_M (   Modifiers,
  Return 
)
Value:
template <typename U = T> \
Modifiers std::enable_if_t<std::is_floating_point_v<U>, Return>

Definition at line 22 of file rect.h.

122 {
123 private:
124 using Type = T;
125
126 public:
127 constexpr TRect() : left_(0), top_(0), right_(0), bottom_(0) {}
128
129 constexpr static TRect MakeLTRB(Type left,
130 Type top,
131 Type right,
132 Type bottom) {
133 return TRect(left, top, right, bottom);
134 }
135
136 constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height) {
137 return TRect(x, y, saturated::Add(x, width), saturated::Add(y, height));
138 }
139
140 constexpr static TRect MakeWH(Type width, Type height) {
141 return TRect(0, 0, width, height);
142 }
143
144 constexpr static TRect MakeOriginSize(const TPoint<Type>& origin,
145 const TSize<Type>& size) {
146 return MakeXYWH(origin.x, origin.y, size.width, size.height);
147 }
148
149 template <class U>
150 constexpr static TRect MakeSize(const TSize<U>& size) {
151 return TRect(0.0, 0.0, size.width, size.height);
152 }
153
154 /// Construct the rectangular bounds of a circle with the supplied
155 /// center point and uniform radius.
156 constexpr static TRect MakeCircleBounds(const TPoint<Type>& center,
157 Type radius) {
158 return MakeLTRB(center.x - radius, center.y - radius, //
159 center.x + radius, center.y + radius);
160 }
161
162 /// Construct the rectangular bounds of a circle with the supplied
163 /// center point and non-uniform horizontal and vertical radii.
164 constexpr static TRect MakeEllipseBounds(const TPoint<Type>& center,
165 const TSize<Type>& radii) {
166 return MakeLTRB(center.x - radii.width, center.y - radii.height, //
167 center.x + radii.width, center.y + radii.height);
168 }
169
170 /// Construct the rectangular bounds of a circle with the supplied
171 /// center point and non-uniform horizontal and vertical radii.
172 constexpr static TRect MakeEllipseBounds(const TPoint<Type>& center,
173 const TPoint<Type>& radii) {
174 return MakeLTRB(center.x - radii.x, center.y - radii.y, //
175 center.x + radii.x, center.y + radii.y);
176 }
177
178 /// Construct a floating point rect |Rect| from another Rect of a
179 /// potentially different storage type (eg. |IRect|).
180 template <class U, class FT = T>
181 constexpr static std::enable_if_t<std::is_floating_point_v<FT>, TRect> Make(
182 const TRect<U>& rect) {
183 return MakeLTRB(
184 static_cast<FT>(rect.GetLeft()), static_cast<FT>(rect.GetTop()),
185 static_cast<FT>(rect.GetRight()), static_cast<FT>(rect.GetBottom()));
186 }
187
188 template <typename U>
189 constexpr static std::optional<TRect> MakePointBounds(const U& value) {
190 return MakePointBounds(value.begin(), value.end());
191 }
192
193 template <typename PointIter>
194 constexpr static std::optional<TRect> MakePointBounds(const PointIter first,
195 const PointIter last) {
196 if (first == last) {
197 return std::nullopt;
198 }
199 auto left = first->x;
200 auto top = first->y;
201 auto right = first->x;
202 auto bottom = first->y;
203 for (auto it = first + 1; it < last; ++it) {
204 left = std::min(left, it->x);
205 top = std::min(top, it->y);
206 right = std::max(right, it->x);
207 bottom = std::max(bottom, it->y);
208 }
209 return TRect::MakeLTRB(left, top, right, bottom);
210 }
211
212 [[nodiscard]] constexpr static TRect MakeMaximum() {
213 return TRect::MakeLTRB(std::numeric_limits<Type>::lowest(),
214 std::numeric_limits<Type>::lowest(),
215 std::numeric_limits<Type>::max(),
216 std::numeric_limits<Type>::max());
217 }
218
219 [[nodiscard]] constexpr bool operator==(const TRect& r) const {
220 return left_ == r.left_ && //
221 top_ == r.top_ && //
222 right_ == r.right_ && //
223 bottom_ == r.bottom_;
224 }
225
226 [[nodiscard]] constexpr TRect Scale(Type scale) const {
227 return TRect(left_ * scale, //
228 top_ * scale, //
229 right_ * scale, //
230 bottom_ * scale);
231 }
232
233 [[nodiscard]] constexpr TRect Scale(Type scale_x, Type scale_y) const {
234 return TRect(left_ * scale_x, //
235 top_ * scale_y, //
236 right_ * scale_x, //
237 bottom_ * scale_y);
238 }
239
240 [[nodiscard]] constexpr TRect Scale(TPoint<T> scale) const {
241 return Scale(scale.x, scale.y);
242 }
243
244 [[nodiscard]] constexpr TRect Scale(TSize<T> scale) const {
245 return Scale(scale.width, scale.height);
246 }
247
248 /// @brief Returns true iff the provided point |p| is inside the
249 /// half-open interior of this rectangle.
250 ///
251 /// For purposes of containment, a rectangle contains points
252 /// along the top and left edges but not points along the
253 /// right and bottom edges so that a point is only ever
254 /// considered inside one of two abutting rectangles.
255 [[nodiscard]] constexpr bool Contains(const TPoint<Type>& p) const {
256 return !this->IsEmpty() && //
257 p.x >= left_ && //
258 p.y >= top_ && //
259 p.x < right_ && //
260 p.y < bottom_;
261 }
262
263 /// @brief Returns true iff the provided point |p| is inside the
264 /// closed-range interior of this rectangle.
265 ///
266 /// Unlike the regular |Contains(TPoint)| method, this method
267 /// considers all points along the boundary of the rectangle
268 /// to be contained within the rectangle - useful for testing
269 /// if vertices that define a filled shape would carry the
270 /// interior of that shape outside the bounds of the rectangle.
271 /// Since both geometries are defining half-open spaces, their
272 /// defining geometry needs to consider their boundaries to
273 /// be equivalent with respect to interior and exterior.
274 [[nodiscard]] constexpr bool ContainsInclusive(const TPoint<Type>& p) const {
275 return !this->IsEmpty() && //
276 p.x >= left_ && //
277 p.y >= top_ && //
278 p.x <= right_ && //
279 p.y <= bottom_;
280 }
281
282 /// @brief Returns true iff this rectangle is not empty and it also
283 /// contains every point considered inside the provided
284 /// rectangle |o| (as determined by |Contains(TPoint)|).
285 ///
286 /// This is similar to a definition where the result is true iff
287 /// the union of the two rectangles is equal to this rectangle,
288 /// ignoring precision issues with performing those operations
289 /// and assuming that empty rectangles are never equal.
290 ///
291 /// An empty rectangle can contain no other rectangle.
292 ///
293 /// An empty rectangle is, however, contained within any
294 /// other non-empy rectangle as the set of points it contains
295 /// is an empty set and so there are no points to fail the
296 /// containment criteria.
297 [[nodiscard]] constexpr bool Contains(const TRect& o) const {
298 return !this->IsEmpty() && //
299 (o.IsEmpty() || (o.left_ >= left_ && //
300 o.top_ >= top_ && //
301 o.right_ <= right_ && //
302 o.bottom_ <= bottom_));
303 }
304
305 template <class U, class FT = T>
306 [[nodiscard]] constexpr std::enable_if_t<std::is_floating_point_v<FT>, bool>
307 Contains(const TRect<U>& o) const {
308 return !this->IsEmpty() && //
309 (o.IsEmpty() || (o.GetLeft() >= left_ && //
310 o.GetTop() >= top_ && //
311 o.GetRight() <= right_ && //
312 o.GetBottom() <= bottom_));
313 }
314
315 /// @brief Returns true if all of the fields of this floating point
316 /// rectangle are finite.
317 ///
318 /// Note that the results of |GetWidth()| and |GetHeight()| may
319 /// still be infinite due to overflow even if the fields themselves
320 /// are finite.
321 ONLY_ON_FLOAT_M([[nodiscard]] constexpr, bool)
322 IsFinite() const {
323 return std::isfinite(left_) && //
324 std::isfinite(top_) && //
325 std::isfinite(right_) && //
326 std::isfinite(bottom_);
327 }
328
329 /// @brief Returns true if either of the width or height are 0, negative,
330 /// or NaN.
331 [[nodiscard]] constexpr bool IsEmpty() const {
332 // Computing the non-empty condition and negating the result causes any
333 // NaN value to return true - i.e. is considered empty.
334 return !(left_ < right_ && top_ < bottom_);
335 }
336
337 /// @brief Returns true if width and height are equal and neither is NaN.
338 [[nodiscard]] constexpr bool IsSquare() const {
339 // empty rectangles can technically be "square", but would be
340 // misleading to most callers. Using |IsEmpty| also prevents
341 // "non-empty and non-overflowing" computations from happening
342 // to be equal to "empty and overflowing" results.
343 // (Consider LTRB(10, 15, MAX-2, MIN+2) which is empty, but both
344 // w/h subtractions equal "5").
345 return !IsEmpty() && (right_ - left_) == (bottom_ - top_);
346 }
347
348 [[nodiscard]] constexpr bool IsMaximum() const {
349 return *this == MakeMaximum();
350 }
351
352 /// @brief Returns the upper left corner of the rectangle as specified
353 /// by the left/top or x/y values when it was constructed.
354 [[nodiscard]] constexpr TPoint<Type> GetOrigin() const {
355 return {left_, top_};
356 }
357
358 /// @brief Returns the size of the rectangle which may be negative in
359 /// either width or height and may have been clipped to the
360 /// maximum integer values for integer rects whose size overflows.
361 [[nodiscard]] constexpr TSize<Type> GetSize() const {
362 return {GetWidth(), GetHeight()};
363 }
364
365 /// @brief Returns the X coordinate of the upper left corner, equivalent
366 /// to |GetOrigin().x|
367 [[nodiscard]] constexpr Type GetX() const { return left_; }
368
369 /// @brief Returns the Y coordinate of the upper left corner, equivalent
370 /// to |GetOrigin().y|
371 [[nodiscard]] constexpr Type GetY() const { return top_; }
372
373 /// @brief Returns the width of the rectangle, equivalent to
374 /// |GetSize().width|
375 [[nodiscard]] constexpr Type GetWidth() const {
376 return saturated::Sub(right_, left_);
377 }
378
379 /// @brief Returns the height of the rectangle, equivalent to
380 /// |GetSize().height|
381 [[nodiscard]] constexpr Type GetHeight() const {
382 return saturated::Sub(bottom_, top_);
383 }
384
385 [[nodiscard]] constexpr auto GetLeft() const { return left_; }
386
387 [[nodiscard]] constexpr auto GetTop() const { return top_; }
388
389 [[nodiscard]] constexpr auto GetRight() const { return right_; }
390
391 [[nodiscard]] constexpr auto GetBottom() const { return bottom_; }
392
393 [[nodiscard]] constexpr TPoint<T> GetLeftTop() const { //
394 return {left_, top_};
395 }
396
397 [[nodiscard]] constexpr TPoint<T> GetRightTop() const {
398 return {right_, top_};
399 }
400
401 [[nodiscard]] constexpr TPoint<T> GetLeftBottom() const {
402 return {left_, bottom_};
403 }
404
405 [[nodiscard]] constexpr TPoint<T> GetRightBottom() const {
406 return {right_, bottom_};
407 }
408
409 /// @brief Get the area of the rectangle, equivalent to |GetSize().Area()|
410 [[nodiscard]] constexpr T Area() const {
411 // TODO(141710): Use saturated math to avoid overflow.
412 return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
413 }
414
415 /// @brief Get the center point as a |Point|.
416 [[nodiscard]] constexpr Point GetCenter() const {
417 return {saturated::AverageScalar(left_, right_),
418 saturated::AverageScalar(top_, bottom_)};
419 }
420
421 [[nodiscard]] constexpr std::array<T, 4> GetLTRB() const {
422 return {left_, top_, right_, bottom_};
423 }
424
425 /// @brief Get the x, y coordinates of the origin and the width and
426 /// height of the rectangle in an array.
427 [[nodiscard]] constexpr std::array<T, 4> GetXYWH() const {
428 return {left_, top_, GetWidth(), GetHeight()};
429 }
430
431 /// @brief Get a version of this rectangle that has a non-negative size.
432 [[nodiscard]] constexpr TRect GetPositive() const {
433 if (!IsEmpty()) {
434 return *this;
435 }
436 return {
437 std::min(left_, right_),
438 std::min(top_, bottom_),
439 std::max(left_, right_),
440 std::max(top_, bottom_),
441 };
442 }
443
444 /// @brief Get the points that represent the 4 corners of this rectangle
445 /// in a Z order that is compatible with triangle strips or a set
446 /// of all zero points if the rectangle is empty.
447 /// The order is: Top left, top right, bottom left, bottom right.
448 [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetPoints() const {
449 if (IsEmpty()) {
450 return {};
451 }
452 return {
453 TPoint{left_, top_},
454 TPoint{right_, top_},
455 TPoint{left_, bottom_},
456 TPoint{right_, bottom_},
457 };
458 }
459
460 [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetTransformedPoints(
461 const Matrix& transform) const {
462 auto points = GetPoints();
463 for (size_t i = 0; i < points.size(); i++) {
464 points[i] = transform * points[i];
465 }
466 return points;
467 }
468
469 /// @brief Creates a new bounding box that contains this transformed
470 /// rectangle, clipped against the near clipping plane if
471 /// necessary.
472 [[nodiscard]] constexpr TRect TransformAndClipBounds(
473 const Matrix& transform) const {
474 if (!transform.HasPerspective2D()) {
475 return TransformBounds(transform);
476 }
477
478 if (IsEmpty()) {
479 return {};
480 }
481
482 auto ul = transform.TransformHomogenous({left_, top_});
483 auto ur = transform.TransformHomogenous({right_, top_});
484 auto ll = transform.TransformHomogenous({left_, bottom_});
485 auto lr = transform.TransformHomogenous({right_, bottom_});
486
487 // It can probably be proven that we only ever have 5 points at most
488 // which happens when only 1 corner is clipped and we get 2 points
489 // in return for it as we interpolate against its neighbors.
490 Point points[8];
491 int index = 0;
492
493 // Process (clip and interpolate) each point against its 2 neighbors:
494 // left, pt, right
495 index = ClipAndInsert(points, index, ll, ul, ur);
496 index = ClipAndInsert(points, index, ul, ur, lr);
497 index = ClipAndInsert(points, index, ur, lr, ll);
498 index = ClipAndInsert(points, index, lr, ll, ul);
499
500 auto bounds = TRect::MakePointBounds(points, points + index);
501 return bounds.value_or(TRect{});
502 }
503
504 /// @brief Creates a new bounding box that contains this transformed
505 /// rectangle.
506 [[nodiscard]] constexpr TRect TransformBounds(const Matrix& transform) const {
507 if (IsEmpty()) {
508 return {};
509 }
510 auto points = GetTransformedPoints(transform);
511 auto bounds = TRect::MakePointBounds(points.begin(), points.end());
512 if (bounds.has_value()) {
513 return bounds.value();
514 }
516 }
517
518 /// @brief Constructs a Matrix that will map all points in the coordinate
519 /// space of the rectangle into a new normalized coordinate space
520 /// where the upper left corner of the rectangle maps to (0, 0)
521 /// and the lower right corner of the rectangle maps to (1, 1).
522 ///
523 /// Empty and non-finite rectangles will return a zero-scaling
524 /// transform that maps all points to (0, 0).
525 [[nodiscard]] constexpr Matrix GetNormalizingTransform() const {
526 if (!IsEmpty()) {
527 Scalar sx = 1.0 / GetWidth();
528 Scalar sy = 1.0 / GetHeight();
529 Scalar tx = left_ * -sx;
530 Scalar ty = top_ * -sy;
531
532 // Exclude NaN and infinities and either scale underflowing to zero
533 if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
534 // clang-format off
535 return Matrix( sx, 0.0f, 0.0f, 0.0f,
536 0.0f, sy, 0.0f, 0.0f,
537 0.0f, 0.0f, 1.0f, 0.0f,
538 tx, ty, 0.0f, 1.0f);
539 // clang-format on
540 }
541 }
542
543 // Map all coordinates to the origin.
544 return Matrix::MakeScale({0.0f, 0.0f, 1.0f});
545 }
546
547 [[nodiscard]] constexpr TRect Union(const TRect& o) const {
548 if (IsEmpty()) {
549 return o;
550 }
551 if (o.IsEmpty()) {
552 return *this;
553 }
554 return {
555 std::min(left_, o.left_),
556 std::min(top_, o.top_),
557 std::max(right_, o.right_),
558 std::max(bottom_, o.bottom_),
559 };
560 }
561
562 [[nodiscard]] constexpr std::optional<TRect> Intersection(
563 const TRect& o) const {
564 if (IntersectsWithRect(o)) {
565 return TRect{
566 std::max(left_, o.left_),
567 std::max(top_, o.top_),
568 std::min(right_, o.right_),
569 std::min(bottom_, o.bottom_),
570 };
571 } else {
572 return std::nullopt;
573 }
574 }
575
576 [[nodiscard]] constexpr TRect IntersectionOrEmpty(const TRect& o) const {
577 return Intersection(o).value_or(TRect());
578 }
579
580 [[nodiscard]] constexpr bool IntersectsWithRect(const TRect& o) const {
581 return !IsEmpty() && //
582 !o.IsEmpty() && //
583 left_ < o.right_ && //
584 top_ < o.bottom_ && //
585 right_ > o.left_ && //
586 bottom_ > o.top_;
587 }
588
589 /// @brief Returns the new boundary rectangle that would result from this
590 /// rectangle being cut out by the specified rectangle.
591 [[nodiscard]] constexpr std::optional<TRect<T>> Cutout(const TRect& o) const {
592 if (IsEmpty()) {
593 // This test isn't just a short-circuit, it also prevents the concise
594 // math below from returning the wrong answer on empty rects.
595 // Once we know that this rectangle is not empty, the math below can
596 // only succeed in computing a value if o is also non-empty and non-nan.
597 // Otherwise, the method returns *this by default.
598 return std::nullopt;
599 }
600
601 const auto& [a_left, a_top, a_right, a_bottom] = GetLTRB(); // Source rect.
602 const auto& [b_left, b_top, b_right, b_bottom] = o.GetLTRB(); // Cutout.
603 if (b_left <= a_left && b_right >= a_right) {
604 if (b_top <= a_top && b_bottom >= a_bottom) {
605 // Full cutout.
606 return std::nullopt;
607 }
608 if (b_top <= a_top && b_bottom > a_top) {
609 // Cuts off the top.
610 return TRect::MakeLTRB(a_left, b_bottom, a_right, a_bottom);
611 }
612 if (b_bottom >= a_bottom && b_top < a_bottom) {
613 // Cuts off the bottom.
614 return TRect::MakeLTRB(a_left, a_top, a_right, b_top);
615 }
616 }
617 if (b_top <= a_top && b_bottom >= a_bottom) {
618 if (b_left <= a_left && b_right > a_left) {
619 // Cuts off the left.
620 return TRect::MakeLTRB(b_right, a_top, a_right, a_bottom);
621 }
622 if (b_right >= a_right && b_left < a_right) {
623 // Cuts off the right.
624 return TRect::MakeLTRB(a_left, a_top, b_left, a_bottom);
625 }
626 }
627
628 return *this;
629 }
630
631 [[nodiscard]] constexpr TRect CutoutOrEmpty(const TRect& o) const {
632 return Cutout(o).value_or(TRect());
633 }
634
635 /// @brief Returns a new rectangle translated by the given offset.
636 [[nodiscard]] constexpr TRect<T> Shift(T dx, T dy) const {
637 return {
638 saturated::Add(left_, dx), //
639 saturated::Add(top_, dy), //
640 saturated::Add(right_, dx), //
641 saturated::Add(bottom_, dy), //
642 };
643 }
644
645 /// @brief Returns a new rectangle translated by the given offset.
646 [[nodiscard]] constexpr TRect<T> Shift(TPoint<T> offset) const {
647 return Shift(offset.x, offset.y);
648 }
649
650 /// @brief Returns a rectangle with expanded edges. Negative expansion
651 /// results in shrinking.
652 [[nodiscard]] constexpr TRect<T> Expand(T left,
653 T top,
654 T right,
655 T bottom) const {
656 return {
657 saturated::Sub(left_, left), //
658 saturated::Sub(top_, top), //
659 saturated::Add(right_, right), //
660 saturated::Add(bottom_, bottom), //
661 };
662 }
663
664 /// @brief Returns a rectangle with expanded edges in all directions.
665 /// Negative expansion results in shrinking.
666 [[nodiscard]] constexpr TRect<T> Expand(T amount) const {
667 return {
668 saturated::Sub(left_, amount), //
669 saturated::Sub(top_, amount), //
670 saturated::Add(right_, amount), //
671 saturated::Add(bottom_, amount), //
672 };
673 }
674
675 /// @brief Returns a rectangle with expanded edges in all directions.
676 /// Negative expansion results in shrinking.
677 [[nodiscard]] constexpr TRect<T> Expand(T horizontal_amount,
678 T vertical_amount) const {
679 return {
680 saturated::Sub(left_, horizontal_amount), //
681 saturated::Sub(top_, vertical_amount), //
682 saturated::Add(right_, horizontal_amount), //
683 saturated::Add(bottom_, vertical_amount), //
684 };
685 }
686
687 /// @brief Returns a rectangle with expanded edges in all directions.
688 /// Negative expansion results in shrinking.
689 [[nodiscard]] constexpr TRect<T> Expand(TPoint<T> amount) const {
690 return Expand(amount.x, amount.y);
691 }
692
693 /// @brief Returns a rectangle with expanded edges in all directions.
694 /// Negative expansion results in shrinking.
695 [[nodiscard]] constexpr TRect<T> Expand(TSize<T> amount) const {
696 return Expand(amount.width, amount.height);
697 }
698
699 /// @brief Returns a new rectangle that represents the projection of the
700 /// source rectangle onto this rectangle. In other words, the source
701 /// rectangle is redefined in terms of the coordinate space of this
702 /// rectangle.
703 [[nodiscard]] constexpr TRect<T> Project(TRect<T> source) const {
704 if (IsEmpty()) {
705 return {};
706 }
707 return source.Shift(-left_, -top_)
708 .Scale(1.0 / static_cast<Scalar>(GetWidth()),
709 1.0 / static_cast<Scalar>(GetHeight()));
710 }
711
712 ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
713 RoundOut(const TRect<U>& r) {
714 return TRect::MakeLTRB(saturated::Cast<U, Type>(floor(r.GetLeft())),
715 saturated::Cast<U, Type>(floor(r.GetTop())),
716 saturated::Cast<U, Type>(ceil(r.GetRight())),
717 saturated::Cast<U, Type>(ceil(r.GetBottom())));
718 }
719
720 ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
721 RoundIn(const TRect<U>& r) {
722 return TRect::MakeLTRB(saturated::Cast<U, Type>(ceil(r.GetLeft())),
723 saturated::Cast<U, Type>(ceil(r.GetTop())),
724 saturated::Cast<U, Type>(floor(r.GetRight())),
725 saturated::Cast<U, Type>(floor(r.GetBottom())));
726 }
727
728 ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
729 Round(const TRect<U>& r) {
730 return TRect::MakeLTRB(saturated::Cast<U, Type>(round(r.GetLeft())),
731 saturated::Cast<U, Type>(round(r.GetTop())),
732 saturated::Cast<U, Type>(round(r.GetRight())),
733 saturated::Cast<U, Type>(round(r.GetBottom())));
734 }
735
736 [[nodiscard]] constexpr static TRect Union(const TRect& a,
737 const std::optional<TRect> b) {
738 return b.has_value() ? a.Union(b.value()) : a;
739 }
740
741 [[nodiscard]] constexpr static TRect Union(const std::optional<TRect> a,
742 const TRect& b) {
743 return a.has_value() ? a->Union(b) : b;
744 }
745
746 [[nodiscard]] constexpr static std::optional<TRect> Union(
747 const std::optional<TRect> a,
748 const std::optional<TRect> b) {
749 return a.has_value() ? Union(a.value(), b) : b;
750 }
751
752 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
753 const TRect& a,
754 const std::optional<TRect> b) {
755 return b.has_value() ? a.Intersection(b.value()) : a;
756 }
757
758 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
759 const std::optional<TRect> a,
760 const TRect& b) {
761 return a.has_value() ? a->Intersection(b) : b;
762 }
763
764 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
765 const std::optional<TRect> a,
766 const std::optional<TRect> b) {
767 return a.has_value() ? Intersection(a.value(), b) : b;
768 }
769
770 private:
771 constexpr TRect(Type left, Type top, Type right, Type bottom)
772 : left_(left), top_(top), right_(right), bottom_(bottom) {}
773
774 Type left_;
775 Type top_;
776 Type right_;
777 Type bottom_;
778
779 static constexpr Scalar kMinimumHomogenous = 1.0f / (1 << 14);
780
781 // Clip p against the near clipping plane (W = kMinimumHomogenous)
782 // and interpolate a crossing point against the nearby neighbors
783 // left and right if p is clipped and either of them is not.
784 // This method can produce 0, 1, or 2 points per call depending on
785 // how many of the points are clipped.
786 // 0 - all points are clipped
787 // 1 - p is unclipped OR
788 // p is clipped and exactly one of the neighbors is not
789 // 2 - p is clipped and both neighbors are not
790 static constexpr int ClipAndInsert(Point clipped[],
791 int index,
792 const Vector3& left,
793 const Vector3& p,
794 const Vector3& right) {
795 if (p.z >= kMinimumHomogenous) {
796 clipped[index++] = {p.x / p.z, p.y / p.z};
797 } else {
798 index = InterpolateAndInsert(clipped, index, p, left);
799 index = InterpolateAndInsert(clipped, index, p, right);
800 }
801 return index;
802 }
803
804 // Interpolate (a clipped) point p against one of its neighbors
805 // and insert the point into the array where the line between them
806 // veers from clipped space to unclipped, if such a point exists.
807 static constexpr int InterpolateAndInsert(Point clipped[],
808 int index,
809 const Vector3& p,
810 const Vector3& neighbor) {
811 if (neighbor.z >= kMinimumHomogenous) {
812 auto t = (kMinimumHomogenous - p.z) / (neighbor.z - p.z);
813 clipped[index++] = {
814 ((1.0f - t) * p.x + t * neighbor.x) / kMinimumHomogenous,
815 ((1.0f - t) * p.y + t * neighbor.y) / kMinimumHomogenous,
816 };
817 }
818 return index;
819 }
820};
821
822using Rect = TRect<Scalar>;
823using IRect32 = TRect<int32_t>;
824using IRect64 = TRect<int64_t>;
825using IRect = IRect64;
826
827#undef ONLY_ON_FLOAT
828#undef ONLY_ON_FLOAT_M
829
830} // namespace impeller
831
832namespace std {
833
834template <class T>
835inline std::ostream& operator<<(std::ostream& out,
836 const impeller::TRect<T>& r) {
837 out << "(" << r.GetLeftTop() << " => " << r.GetRightBottom() << ")";
838 return out;
839}
840
841} // namespace std
842
843#endif // FLUTTER_IMPELLER_GEOMETRY_RECT_H_
int32_t value
int32_t x
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
#define FML_UNREACHABLE()
Definition logging.h:128
#define ONLY_ON_FLOAT_M(Modifiers, Return)
Definition rect.h:22
double y
bool Contains(const Container &container, const Value &value)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
TRect< int32_t > IRect32
Definition rect.h:823
float Scalar
Definition scalar.h:19
TRect< Scalar > Rect
Definition rect.h:822
TPoint< Scalar > Point
Definition point.h:426
IRect64 IRect
Definition rect.h:825
TRect< int64_t > IRect64
Definition rect.h:824
Definition ref_ptr.h:261
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
Definition arc.h:141
int32_t height
int32_t width
constexpr TPoint< T > GetLeftTop() const
Definition rect.h:393
constexpr TPoint< T > GetRightBottom() const
Definition rect.h:405
std::vector< Point > points