Flutter Impeller
arc.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 namespace impeller {
8 
9 Arc::Arc(const Rect& bounds, Degrees start, Degrees sweep, bool include_center)
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 }
35 
37  size_t count = 2;
38  for (size_t i = 0; i < quadrant_count; i++) {
39  count += quadrants[i].GetPointCount();
40  }
41  return count;
42 }
43 
44 const Arc::Iteration Arc::ComputeCircleArcIterations(size_t step_count) {
45  return {
46  {1.0f, 0.0f},
47  {1.0f, 0.0f},
48  4u,
49  {
50  {kQuadrantAxes[0], 1u, step_count},
51  {kQuadrantAxes[1], 0u, step_count},
52  {kQuadrantAxes[2], 0u, step_count},
53  {kQuadrantAxes[3], 0u, step_count},
54  {{}, 0u, 0u},
55  },
56  };
57 }
58 
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 }
101 
103  bool simplify_360) const {
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 }
179 
180 } // namespace impeller
float Scalar
Definition: scalar.h:19
TRect< Scalar > Rect
Definition: rect.h:792
static constexpr impeller::Vector2 kQuadrantAxes[4]
Definition: point.h:335
size_t GetPointCount() const
Definition: arc.h:50
impeller::Vector2 end
Definition: arc.h:59
impeller::Vector2 start
Definition: arc.h:58
size_t GetPointCount() const
Definition: arc.cc:36
Quadrant quadrants[9]
Definition: arc.h:86
size_t quadrant_count
Definition: arc.h:63
Iteration ComputeIterations(size_t step_count, bool simplify_360=true) const
Definition: arc.cc:102
Arc(const Rect &bounds, Degrees start, Degrees sweep, bool include_center)
Definition: arc.cc:9
Rect GetTightArcBounds() const
Definition: arc.cc:59
constexpr bool IsFullCircle() const
Definition: arc.h:114
Scalar degrees
Definition: scalar.h:77
constexpr bool IsFinite() const
Definition: scalar.h:87
constexpr Degrees GetPositive() const
Definition: scalar.h:111
static Vector2 CosSin(Radians radians)
Definition: matrix.h:618
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:165
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
IsFinite() const
Returns true if all of the fields of this floating point rectangle are finite.
Definition: rect.h:292
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386
const size_t start
const size_t end