Flutter Impeller
impeller::Arc Struct Reference

#include <arc.h>

Classes

struct  Iteration
 

Public Member Functions

 Arc (const Rect &bounds, Degrees start, Degrees sweep, bool include_center)
 
const RectGetOvalBounds () const
 Return the bounds of the oval in which this arc is inscribed. More...
 
const Point GetOvalCenter () const
 Returns the center of the oval bounds. More...
 
const Size GetOvalSize () const
 Returns the size of the oval bounds. More...
 
Rect GetTightArcBounds () const
 
constexpr Degrees GetStart () const
 
constexpr Degrees GetSweep () const
 
constexpr bool IncludeCenter () const
 
constexpr bool IsPerfectCircle () const
 
constexpr bool IsFullCircle () const
 
Iteration ComputeIterations (size_t step_count, bool simplify_360=true) const
 

Detailed Description

Definition at line 13 of file arc.h.

Constructor & Destructor Documentation

◆ Arc()

impeller::Arc::Arc ( const Rect bounds,
Degrees  start,
Degrees  sweep,
bool  include_center 
)

Definition at line 9 of file arc.cc.

10  : bounds_(bounds), include_center_(include_center) {
11  if (bounds.IsFinite() && start.IsFinite() && sweep.IsFinite()) {
12  if (sweep.degrees < 0) {
13  start = start + sweep;
14  sweep = -sweep;
15  }
16  if (sweep.degrees > 360) {
17  // We need to represent over-sweeping a full circle for the case where
18  // we will be stroking the circle with the center incuded where we
19  // stroke the entire perimeter, but the two segments that connect to
20  // the center are at the proper angles.
21  // Normalize to less than 720.
22  sweep.degrees = 360.0f + std::fmodf(sweep.degrees, 360.0f);
23  }
24  } else {
25  // Don't bother sweeping any distance if anything is non-finite.
26  sweep = Degrees(0);
27  if (!start.IsFinite() || !bounds.IsFinite()) {
28  // We can maintain start if both it and bounds are finite.
29  start = Degrees(0);
30  }
31  }
32  start_ = start;
33  sweep_ = sweep;
34 }
const size_t start

References impeller::Degrees::degrees, impeller::TRect< T >::IsFinite(), impeller::Degrees::IsFinite(), and start.

Member Function Documentation

◆ ComputeIterations()

Arc::Iteration impeller::Arc::ComputeIterations ( size_t  step_count,
bool  simplify_360 = true 
) const

Return an |ArcIteration| that explains how to generate vertices for the arc with the indicated number of steps in each full quadrant. The step_count is typically chosen based on the size of the bounds and the scale at which the arc is being drawn and so the computation of the step_count requirements is left to the caller.

If the sweep is more than 360 degrees then the code may simplify the iteration to a simple circle, but only if the simplify_360 parameter is true.

Definition at line 102 of file arc.cc.

103  {
104  if (sweep_.degrees == 0) {
105  return {};
106  }
107 
108  FML_DCHECK(sweep_.degrees >= 0);
109 
110  if (simplify_360 && sweep_.degrees >= 360) {
111  return ComputeCircleArcIterations(step_count);
112  }
113  FML_DCHECK(sweep_.degrees < 720);
114 
115  Degrees start = start_.GetPositive();
116  Degrees end = start + sweep_;
117  FML_DCHECK(start.degrees >= 0.0f && start.degrees < 360.0f);
118  FML_DCHECK(end >= start);
119  FML_DCHECK(end.degrees < start.degrees + (simplify_360 ? 360.0f : 720.0f));
120 
121  Iteration iterations;
122  iterations.start = impeller::Matrix::CosSin(start);
123  iterations.end = impeller::Matrix::CosSin(end);
124 
125  // We nudge the start and stop by 1/10th of a step so we don't end
126  // up with degenerately small steps at the start and end of the
127  // arc.
128  Degrees nudge = Degrees((90.0f / step_count) * 0.1f);
129 
130  if ((start + nudge) >= (end - nudge)) {
131  iterations.quadrant_count = 0u;
132  return iterations;
133  }
134 
135  int cur_quadrant =
136  static_cast<int>(std::floor((start + nudge).degrees / 90.0f));
137  int end_quadrant =
138  static_cast<int>(std::floor((end - nudge).degrees / 90.0f));
139  FML_DCHECK(cur_quadrant >= 0 && //
140  cur_quadrant <= 4);
141  FML_DCHECK(end_quadrant >= cur_quadrant && //
142  end_quadrant <= cur_quadrant + 8);
143  FML_DCHECK(cur_quadrant * 90 <= (start + nudge).degrees);
144  FML_DCHECK(end_quadrant * 90 + 90 >= (end - nudge).degrees);
145 
146  auto next_step = [step_count](Degrees angle, int quadrant) -> size_t {
147  Scalar quadrant_fract = angle.degrees / 90.0f - quadrant;
148  return static_cast<size_t>(std::ceil(quadrant_fract * step_count));
149  };
150 
151  int i = 0;
152  iterations.quadrants[i] = {
153  kQuadrantAxes[cur_quadrant & 3],
154  next_step(start + nudge, cur_quadrant),
155  step_count,
156  };
157  if (iterations.quadrants[0].end_index > iterations.quadrants[0].start_index) {
158  i++;
159  }
160  while (cur_quadrant < end_quadrant) {
161  iterations.quadrants[i++] = {
162  kQuadrantAxes[(++cur_quadrant) % 4],
163  0u,
164  step_count,
165  };
166  }
167  FML_DCHECK(i <= 9);
168  if (i > 0) {
169  iterations.quadrants[i - 1].end_index =
170  next_step(end - nudge, cur_quadrant);
171  if (iterations.quadrants[i - 1].end_index <=
172  iterations.quadrants[i - 1].start_index) {
173  i--;
174  }
175  }
176  iterations.quadrant_count = i;
177  return iterations;
178 }
float Scalar
Definition: scalar.h:19
static constexpr impeller::Vector2 kQuadrantAxes[4]
Definition: point.h:335
Scalar degrees
Definition: scalar.h:77
constexpr Degrees GetPositive() const
Definition: scalar.h:111
static Vector2 CosSin(Radians radians)
Definition: matrix.h:618
const size_t end

References impeller::Matrix::CosSin(), impeller::Degrees::degrees, impeller::Arc::Iteration::end, end, impeller::Arc::Iteration::Quadrant::end_index, impeller::Degrees::GetPositive(), impeller::kQuadrantAxes, impeller::Arc::Iteration::quadrant_count, impeller::Arc::Iteration::quadrants, impeller::Arc::Iteration::start, start, and impeller::Arc::Iteration::Quadrant::start_index.

Referenced by impeller::ArcStrokeGeometry::Dispatch(), impeller::Tessellator::FilledArc(), impeller::StrokePathSegmentReceiver::RecordArc(), impeller::Tessellator::StrokedArc(), and impeller::testing::TEST().

◆ GetOvalBounds()

const Rect& impeller::Arc::GetOvalBounds ( ) const
inline

Return the bounds of the oval in which this arc is inscribed.

Definition at line 94 of file arc.h.

94 { return bounds_; }

Referenced by impeller::Canvas::DrawArc(), impeller::Tessellator::FilledArc(), std::operator<<(), and impeller::Tessellator::StrokedArc().

◆ GetOvalCenter()

const Point impeller::Arc::GetOvalCenter ( ) const
inline

Returns the center of the oval bounds.

Definition at line 97 of file arc.h.

97 { return bounds_.GetCenter(); }
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386

References impeller::TRect< T >::GetCenter().

Referenced by impeller::ArcStrokeGeometry::Dispatch().

◆ GetOvalSize()

const Size impeller::Arc::GetOvalSize ( ) const
inline

Returns the size of the oval bounds.

Definition at line 100 of file arc.h.

100 { return bounds_.GetSize(); }
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:331

References impeller::TRect< T >::GetSize().

Referenced by impeller::ArcStrokeGeometry::Dispatch(), impeller::Tessellator::FilledArc(), and impeller::Tessellator::StrokedArc().

◆ GetStart()

constexpr Degrees impeller::Arc::GetStart ( ) const
inlineconstexpr

Definition at line 106 of file arc.h.

106 { return start_; }

Referenced by impeller::Canvas::DrawArc(), and std::operator<<().

◆ GetSweep()

constexpr Degrees impeller::Arc::GetSweep ( ) const
inlineconstexpr

Definition at line 108 of file arc.h.

108 { return sweep_; }

Referenced by impeller::Canvas::DrawArc(), and std::operator<<().

◆ GetTightArcBounds()

Rect impeller::Arc::GetTightArcBounds ( ) const

Return the tight bounds of the arc taking into account its specific geometry such as the start and end angles and the center (if included).

Definition at line 59 of file arc.cc.

59  {
60  if (IsFullCircle()) {
61  return bounds_;
62  }
63 
64  Degrees start_angle = start_.GetPositive();
65  Degrees end_angle = start_angle + sweep_;
66  FML_DCHECK(start_angle.degrees >= 0 && start_angle.degrees < 360);
67  FML_DCHECK(end_angle > start_angle && end_angle.degrees < 720);
68 
69  // 1. start vector
70  // 2. end vector
71  // 3. optional center
72  // 4-7. optional quadrant extrema
73  Point extrema[7];
74  int count = 0;
75 
76  extrema[count++] = Matrix::CosSin(start_angle);
77  extrema[count++] = Matrix::CosSin(end_angle);
78 
79  if (include_center_) {
80  extrema[count++] = {0, 0};
81  }
82 
83  // cur_axis will be pre-incremented before recording the following axis
84  int cur_axis = std::floor(start_angle.degrees / 90.0f);
85  // end_axis is a non-inclusive end of the range
86  int end_axis = std::ceil(end_angle.degrees / 90.0f);
87  while (++cur_axis < end_axis) {
88  extrema[count++] = kQuadrantAxes[cur_axis & 3];
89  }
90 
91  FML_DCHECK(count <= 7);
92 
93  Point center = bounds_.GetCenter();
94  Size radii = bounds_.GetSize() * 0.5f;
95 
96  for (int i = 0; i < count; i++) {
97  extrema[i] = center + extrema[i] * radii;
98  }
99  return Rect::MakePointBounds(extrema, extrema + count).value_or(Rect());
100 }
TRect< Scalar > Rect
Definition: rect.h:792
TPoint< Scalar > Point
Definition: point.h:327
TSize< Scalar > Size
Definition: size.h:159
constexpr bool IsFullCircle() const
Definition: arc.h:114
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:165

References impeller::Matrix::CosSin(), impeller::Degrees::degrees, impeller::TRect< T >::GetCenter(), impeller::Degrees::GetPositive(), impeller::TRect< T >::GetSize(), IsFullCircle(), impeller::kQuadrantAxes, and impeller::TRect< Scalar >::MakePointBounds().

Referenced by impeller::ArcStrokeGeometry::GetCoverage().

◆ IncludeCenter()

constexpr bool impeller::Arc::IncludeCenter ( ) const
inlineconstexpr

◆ IsFullCircle()

constexpr bool impeller::Arc::IsFullCircle ( ) const
inlineconstexpr

Definition at line 114 of file arc.h.

114 { return sweep_.degrees >= 360.0f; }

References impeller::Degrees::degrees.

Referenced by impeller::Canvas::DrawArc(), and GetTightArcBounds().

◆ IsPerfectCircle()

constexpr bool impeller::Arc::IsPerfectCircle ( ) const
inlineconstexpr

Definition at line 112 of file arc.h.

112 { return bounds_.IsSquare(); }
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
Definition: rect.h:308

References impeller::TRect< T >::IsSquare().

Referenced by impeller::ArcGeometry::ArcGeometry(), and impeller::Tessellator::StrokedArc().


The documentation for this struct was generated from the following files: