GrOctoBounds.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright 2019 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #ifndef GrOctoBounds_DEFINED
  8. #define GrOctoBounds_DEFINED
  9. #include "include/core/SkRect.h"
  10. #include <functional>
  11. /**
  12. * This class is composed of two bounding boxes: one in device space, and one in a 45-degree rotated
  13. * space.
  14. *
  15. * The 45-degree bounding box resides in "| 1 -1 | * coords" space.
  16. * | 1 1 |
  17. *
  18. * The intersection of these two boxes defines the bounding octagon of a shape.
  19. *
  20. * Furthermore, both bounding boxes are fully tightened. This means we can blindly find the
  21. * intersections between each diagonal and its vertical and horizontal neighbors, and be left with
  22. * 8 points that define a convex (possibly degenerate) octagon.
  23. */
  24. class GrOctoBounds {
  25. public:
  26. GrOctoBounds() = default;
  27. GrOctoBounds(const SkRect& bounds, const SkRect& bounds45) {
  28. this->set(bounds, bounds45);
  29. }
  30. void set(const SkRect& bounds, const SkRect& bounds45) {
  31. fBounds = bounds;
  32. fBounds45 = bounds45;
  33. SkDEBUGCODE(this->validateBoundsAreTight());
  34. }
  35. bool operator==(const GrOctoBounds& that) const {
  36. return fBounds == that.fBounds && fBounds45 == that.fBounds45;
  37. }
  38. bool operator!=(const GrOctoBounds& that) const { return !(*this == that); }
  39. const SkRect& bounds() const { return fBounds; }
  40. float left() const { return fBounds.left(); }
  41. float top() const { return fBounds.top(); }
  42. float right() const { return fBounds.right(); }
  43. float bottom() const { return fBounds.bottom(); }
  44. // The 45-degree bounding box resides in "| 1 -1 | * coords" space.
  45. // | 1 1 |
  46. const SkRect& bounds45() const { return fBounds45; }
  47. float left45() const { return fBounds45.left(); }
  48. float top45() const { return fBounds45.top(); }
  49. float right45() const { return fBounds45.right(); }
  50. float bottom45() const { return fBounds45.bottom(); }
  51. void roundOut(SkIRect* out) const {
  52. // The octagon is the intersection of fBounds and fBounds45 (see the comment at the start of
  53. // the class). The octagon's bounding box is therefore just fBounds. And the integer
  54. // bounding box can be found by simply rounding out fBounds.
  55. fBounds.roundOut(out);
  56. }
  57. GrOctoBounds makeOffset(float dx, float dy) const {
  58. GrOctoBounds offset;
  59. offset.setOffset(*this, dx, dy);
  60. return offset;
  61. }
  62. void setOffset(const GrOctoBounds& octoBounds, float dx, float dy) {
  63. fBounds = octoBounds.fBounds.makeOffset(dx, dy);
  64. fBounds45 = octoBounds.fBounds45.makeOffset(dx - dy, dx + dy);
  65. SkDEBUGCODE(this->validateBoundsAreTight());
  66. }
  67. void outset(float radius) {
  68. fBounds.outset(radius, radius);
  69. fBounds45.outset(radius*SK_ScalarSqrt2, radius*SK_ScalarSqrt2);
  70. SkDEBUGCODE(this->validateBoundsAreTight());
  71. }
  72. // Clips the octo bounds by a clip rect and ensures the resulting bounds are fully tightened.
  73. // Returns false if the octagon and clipRect do not intersect at all.
  74. //
  75. // NOTE: Does not perform a trivial containment test before the clip routine. It is probably a
  76. // good idea to not call this method if 'this->bounds()' are fully contained within 'clipRect'.
  77. bool SK_WARN_UNUSED_RESULT clip(const SkIRect& clipRect);
  78. // The 45-degree bounding box resides in "| 1 -1 | * coords" space.
  79. // | 1 1 |
  80. //
  81. // i.e., | x45 | = | x - y |
  82. // | y45 | = | x + y |
  83. //
  84. // These methods transform points between device space and 45-degree space.
  85. constexpr static float Get_x45(float x, float y) { return x - y; }
  86. constexpr static float Get_y45(float x, float y) { return x + y; }
  87. constexpr static float Get_x(float x45, float y45) { return (x45 + y45) * .5f; }
  88. constexpr static float Get_y(float x45, float y45) { return (y45 - x45) * .5f; }
  89. #if defined(SK_DEBUG) || defined(GR_TEST_UTILS)
  90. void validateBoundsAreTight() const;
  91. void validateBoundsAreTight(const std::function<void(
  92. bool cond, const char* file, int line, const char* code)>& validateFn) const;
  93. #endif
  94. private:
  95. SkRect fBounds;
  96. SkRect fBounds45;
  97. };
  98. #endif