Flutter Impeller
arc.h
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 #ifndef FLUTTER_IMPELLER_GEOMETRY_ARC_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_ARC_H_
7 
10 
11 namespace impeller {
12 
13 struct Arc {
14  /// A structure to describe the iteration through a set of angle vectors
15  /// in a |Trigs| structure to render the points along an arc. The start
16  /// and end vectors and each iteration's axis vector are all unit vectors
17  /// that point in the direction of the point on the circle to be emitted.
18  ///
19  /// Each vector should be rendered by multiplying it by the radius of the
20  /// circle, or in the case of a stroked arc, by the inner and outer radii
21  /// of the sides of the stroke.
22  ///
23  /// - The start vector will always be rendered first.
24  /// - Then each quadrant will be iterated by composing the trigs vectors
25  /// with the given axis vector, iterating from the start index (inclusive)
26  /// to the end index (exclusive) of the vector of |Trig| values.
27  /// - Finally the end vector will be rendered.
28  /// For example:
29  /// Insert(arc_iteration.start * radius);
30  /// for (size_t i = 0u; i < arc_iteration.quadrant_count; i++) {
31  /// Quadrant quadrant = arc_iteration.quadrants[i];
32  /// for (j = quadrant.start_index; j < quadrant.end_index; j++) {
33  /// Insert(trigs[j] * quadrant.axis * radius);
34  /// }
35  /// }
36  /// Insert(arc_iteration.end * radius);
37  ///
38  /// The rendering routine may adjust the manner/order in which those vertices
39  /// are inserted into the vertex buffer to optimally match the vertex triangle
40  /// mode it plans to use, but the description above represents the basic
41  /// technique to compute the points along the actual curve.
42  struct Iteration {
43  // The axis to multiply by each |Trig| value and the half-open [start, end)
44  // range of indices into the associated |Trig| vector over which to compute.
45  struct Quadrant {
47  size_t start_index = 0u;
48  size_t end_index = 0u;
49 
50  size_t GetPointCount() const {
51  FML_DCHECK(start_index < end_index);
52  return end_index - start_index;
53  }
54  };
55 
56  // The true begin and end angles of the arc, expressed as unit direction
57  // vectors.
60 
61  // The variable number of quadrants that have to be iterated and
62  // cross-referenced with values in a |Trigs| object.
63  size_t quadrant_count = 0u;
64 
65  // Normally, we have at most 5 |Quadrant| entries when an arc starts
66  // and ends in the same quadrant with the start angle later in the
67  // quadrant than the end angle.
68  //
69  // Worst case:
70  // - First iteration goes from the start angle to the end of that quadrant.
71  // - Then 3 full iterations for the 3 other full quarter circles.
72  // - Then a last iteration that goes from the start of that quadrant to the
73  // end angle.
74  //
75  // However, when we have an arc that sweeps past a full circle, then we
76  // can have up to 9 |Quadrant| entries. The extra quadrants are only
77  // interesting in the case where the arc is stroked and we are including
78  // the center. Such an arc should look like a complete circle with an
79  // additional pie sliced cut into it, but not removed. Expressing that
80  // case with one continuous path may require up to 7 full quadrants and
81  // 2 partial quadrants for 9 total quadrants in this degenerate stroking
82  // case.
83  //
84  // We can also have 0 quadrants for arcs that are smaller than the
85  // step size of the pixel-radius |Trigs| vector.
87 
88  size_t GetPointCount() const;
89  };
90 
91  Arc(const Rect& bounds, Degrees start, Degrees sweep, bool include_center);
92 
93  /// Return the bounds of the oval in which this arc is inscribed.
94  const Rect& GetOvalBounds() const { return bounds_; }
95 
96  /// Returns the center of the oval bounds.
97  const Point GetOvalCenter() const { return bounds_.GetCenter(); }
98 
99  /// Returns the size of the oval bounds.
100  const Size GetOvalSize() const { return bounds_.GetSize(); }
101 
102  /// Return the tight bounds of the arc taking into account its specific
103  /// geometry such as the start and end angles and the center (if included).
104  Rect GetTightArcBounds() const;
105 
106  constexpr Degrees GetStart() const { return start_; }
107 
108  constexpr Degrees GetSweep() const { return sweep_; }
109 
110  constexpr bool IncludeCenter() const { return include_center_; }
111 
112  constexpr bool IsPerfectCircle() const { return bounds_.IsSquare(); }
113 
114  constexpr bool IsFullCircle() const { return sweep_.degrees >= 360.0f; }
115 
116  /// Return an |ArcIteration| that explains how to generate vertices for
117  /// the arc with the indicated number of steps in each full quadrant.
118  /// The step_count is typically chosen based on the size of the bounds
119  /// and the scale at which the arc is being drawn and so the computation
120  /// of the step_count requirements is left to the caller.
121  ///
122  /// If the sweep is more than 360 degrees then the code may simplify
123  /// the iteration to a simple circle, but only if the simplify_360
124  /// parameter is true.
125  Iteration ComputeIterations(size_t step_count,
126  bool simplify_360 = true) const;
127 
128  private:
129  Rect bounds_;
130  Degrees start_;
131  Degrees sweep_;
132  bool include_center_;
133 
134  static const Iteration ComputeCircleArcIterations(size_t step_count);
135 };
136 
137 } // namespace impeller
138 
139 namespace std {
140 
141 inline std::ostream& operator<<(std::ostream& out, const impeller::Arc& a) {
142  out << "Arc(" << a.GetOvalBounds() << ", " << a.GetStart() << " + "
143  << a.GetSweep()
144  << (a.IncludeCenter() ? ", with center)" : ", without center)");
145  return out;
146 }
147 
148 } // namespace std
149 
150 #endif // FLUTTER_IMPELLER_GEOMETRY_ARC_H_
Definition: comparable.h:95
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
Definition: arc.h:141
size_t GetPointCount() const
Definition: arc.h:50
impeller::Vector2 axis
Definition: arc.h:46
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 IncludeCenter() const
Definition: arc.h:110
constexpr bool IsFullCircle() const
Definition: arc.h:114
const Size GetOvalSize() const
Returns the size of the oval bounds.
Definition: arc.h:100
constexpr bool IsPerfectCircle() const
Definition: arc.h:112
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
Definition: arc.h:94
const Point GetOvalCenter() const
Returns the center of the oval bounds.
Definition: arc.h:97
constexpr Degrees GetSweep() const
Definition: arc.h:108
constexpr Degrees GetStart() const
Definition: arc.h:106
Scalar degrees
Definition: scalar.h:77
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
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
Definition: rect.h:308
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386
const size_t start