| 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
5 #include "flutter/impeller/geometry/arc.h"
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
36 size_t Arc::Iteration::GetPointCount() const {
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
59 Rect Arc::GetTightArcBounds() const {
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
102 Arc::Iteration Arc::ComputeIterations(size_t step_count,
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
arc.h
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:792
impeller::kQuadrantAxes
static constexpr impeller::Vector2 kQuadrantAxes[4]
Definition: point.h:335
impeller::Arc::Iteration::Quadrant::GetPointCount
size_t GetPointCount() const
Definition: arc.h:50
impeller::Arc::Iteration::Quadrant::start_index
size_t start_index
Definition: arc.h:47
impeller::Arc::Iteration::Quadrant::end_index
size_t end_index
Definition: arc.h:48
impeller::Arc::Iteration
Definition: arc.h:42
impeller::Arc::Iteration::end
impeller::Vector2 end
Definition: arc.h:59
impeller::Arc::Iteration::start
impeller::Vector2 start
Definition: arc.h:58
impeller::Arc::Iteration::GetPointCount
size_t GetPointCount() const
Definition: arc.cc:36
impeller::Arc::Iteration::quadrants
Quadrant quadrants[9]
Definition: arc.h:86
impeller::Arc::Iteration::quadrant_count
size_t quadrant_count
Definition: arc.h:63
impeller::Arc::ComputeIterations
Iteration ComputeIterations(size_t step_count, bool simplify_360=true) const
Definition: arc.cc:102
impeller::Arc::Arc
Arc(const Rect &bounds, Degrees start, Degrees sweep, bool include_center)
Definition: arc.cc:9
impeller::Arc::GetTightArcBounds
Rect GetTightArcBounds() const
Definition: arc.cc:59
impeller::Arc::IsFullCircle
constexpr bool IsFullCircle() const
Definition: arc.h:114
impeller::Degrees
Definition: scalar.h:76
impeller::Degrees::degrees
Scalar degrees
Definition: scalar.h:77
impeller::Degrees::IsFinite
constexpr bool IsFinite() const
Definition: scalar.h:87
impeller::Degrees::GetPositive
constexpr Degrees GetPositive() const
Definition: scalar.h:111
impeller::Matrix::CosSin
static Vector2 CosSin(Radians radians)
Definition: matrix.h:685
impeller::TPoint< Scalar >
impeller::TRect< Scalar >
impeller::TRect< Scalar >::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:165
impeller::TRect::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
impeller::TRect::IsFinite
IsFinite() const
Returns true if all of the fields of this floating point rectangle are finite.
Definition: rect.h:292
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386
impeller::TSize< Scalar >
start
const size_t start
Definition: tessellator_libtess.cc:62
end
const size_t end
Definition: tessellator_libtess.cc:63