| Flutter Impeller |

path_builder.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 "path_builder.h"
6
7 #include <cmath>
8
9 namespace impeller {
10
11 PathBuilder::PathBuilder() = default;
12
13 PathBuilder::~PathBuilder() = default;
14
15 Path PathBuilder::CopyPath(FillType fill) const {
16 auto path = prototype_.Clone();
17 path.SetFillType(fill);
18 return path;
19 }
20
21 Path PathBuilder::TakePath(FillType fill) {
22 auto path = std::move(prototype_);
23 path.SetFillType(fill);
24 path.SetConvexity(convexity_);
25 if (!did_compute_bounds_) {
26 path.ComputeBounds();
27 }
28 did_compute_bounds_ = false;
29 return path;
30 }
31
32 void PathBuilder::Reserve(size_t point_size, size_t verb_size) {
33 prototype_.points_.reserve(point_size);
34 prototype_.points_.reserve(verb_size);
35 }
36
37 PathBuilder& PathBuilder::MoveTo(Point point, bool relative) {
38 current_ = relative ? current_ + point : point;
39 subpath_start_ = current_;
40 prototype_.AddContourComponent(current_);
41 return *this;
42 }
43
44 PathBuilder& PathBuilder::Close() {
45 LineTo(subpath_start_);
46 prototype_.SetContourClosed(true);
47 prototype_.AddContourComponent(current_);
48 return *this;
49 }
50
51 PathBuilder& PathBuilder::LineTo(Point point, bool relative) {
52 point = relative ? current_ + point : point;
53 prototype_.AddLinearComponent(current_, point);
54 current_ = point;
55 return *this;
56 }
57
58 PathBuilder& PathBuilder::HorizontalLineTo(Scalar x, bool relative) {
59 Point endpoint =
60 relative ? Point{current_.x + x, current_.y} : Point{x, current_.y};
61 prototype_.AddLinearComponent(current_, endpoint);
62 current_ = endpoint;
63 return *this;
64 }
65
66 PathBuilder& PathBuilder::VerticalLineTo(Scalar y, bool relative) {
67 Point endpoint =
68 relative ? Point{current_.x, current_.y + y} : Point{current_.x, y};
69 prototype_.AddLinearComponent(current_, endpoint);
70 current_ = endpoint;
71 return *this;
72 }
73
74 PathBuilder& PathBuilder::QuadraticCurveTo(Point controlPoint,
75 Point point,
76 bool relative) {
77 point = relative ? current_ + point : point;
78 controlPoint = relative ? current_ + controlPoint : controlPoint;
79 prototype_.AddQuadraticComponent(current_, controlPoint, point);
80 current_ = point;
81 return *this;
82 }
83
84 PathBuilder& PathBuilder::SetConvexity(Convexity value) {
85 convexity_ = value;
86 return *this;
87 }
88
89 PathBuilder& PathBuilder::CubicCurveTo(Point controlPoint1,
90 Point controlPoint2,
91 Point point,
92 bool relative) {
93 controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
94 controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
95 point = relative ? current_ + point : point;
96 prototype_.AddCubicComponent(current_, controlPoint1, controlPoint2, point);
97 current_ = point;
98 return *this;
99 }
100
101 PathBuilder& PathBuilder::AddQuadraticCurve(Point p1, Point cp, Point p2) {
102 MoveTo(p1);
103 prototype_.AddQuadraticComponent(p1, cp, p2);
104 return *this;
105 }
106
107 PathBuilder& PathBuilder::AddCubicCurve(Point p1,
108 Point cp1,
109 Point cp2,
110 Point p2) {
111 MoveTo(p1);
112 prototype_.AddCubicComponent(p1, cp1, cp2, p2);
113 return *this;
114 }
115
116 PathBuilder& PathBuilder::AddRect(Rect rect) {
117 auto origin = rect.GetOrigin();
118 auto size = rect.GetSize();
119
120 auto tl = origin;
121 auto bl = origin + Point{0.0, size.height};
122 auto br = origin + size;
123 auto tr = origin + Point{size.width, 0.0};
124
125 MoveTo(tl);
126 LineTo(tr);
127 LineTo(br);
128 LineTo(bl);
129 Close();
130
131 return *this;
132 }
133
134 PathBuilder& PathBuilder::AddCircle(const Point& c, Scalar r) {
135 return AddOval(Rect::MakeXYWH(c.x - r, c.y - r, 2.0f * r, 2.0f * r));
136 }
137
138 PathBuilder& PathBuilder::AddRoundedRect(Rect rect, Scalar radius) {
139 return radius <= 0.0 ? AddRect(rect)
140 : AddRoundedRect(rect, RoundingRadii(radius));
141 }
142
143 PathBuilder& PathBuilder::AddRoundedRect(Rect rect, Size radii) {
144 return radii.width <= 0 || radii.height <= 0
145 ? AddRect(rect)
146 : AddRoundedRect(rect, RoundingRadii(radii));
147 }
148
149 PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
150 if (radii.AreAllZero()) {
151 return AddRect(rect);
152 }
153
154 auto rect_origin = rect.GetOrigin();
155 auto rect_size = rect.GetSize();
156
157 current_ = rect_origin + Point{radii.top_left.x, 0.0};
158
159 MoveTo({rect_origin.x + radii.top_left.x, rect_origin.y});
160
161 //----------------------------------------------------------------------------
162 // Top line.
163 //
164 prototype_.AddLinearComponent(
165 {rect_origin.x + radii.top_left.x, rect_origin.y},
166 {rect_origin.x + rect_size.width - radii.top_right.x, rect_origin.y});
167
168 //----------------------------------------------------------------------------
169 // Top right arc.
170 //
171 AddRoundedRectTopRight(rect, radii);
172
173 //----------------------------------------------------------------------------
174 // Right line.
175 //
176 prototype_.AddLinearComponent(
177 {rect_origin.x + rect_size.width, rect_origin.y + radii.top_right.y},
178 {rect_origin.x + rect_size.width,
179 rect_origin.y + rect_size.height - radii.bottom_right.y});
180
181 //----------------------------------------------------------------------------
182 // Bottom right arc.
183 //
184 AddRoundedRectBottomRight(rect, radii);
185
186 //----------------------------------------------------------------------------
187 // Bottom line.
188 //
189 prototype_.AddLinearComponent(
190 {rect_origin.x + rect_size.width - radii.bottom_right.x,
191 rect_origin.y + rect_size.height},
192 {rect_origin.x + radii.bottom_left.x, rect_origin.y + rect_size.height});
193
194 //----------------------------------------------------------------------------
195 // Bottom left arc.
196 //
197 AddRoundedRectBottomLeft(rect, radii);
198
199 //----------------------------------------------------------------------------
200 // Left line.
201 //
202 prototype_.AddLinearComponent(
203 {rect_origin.x, rect_origin.y + rect_size.height - radii.bottom_left.y},
204 {rect_origin.x, rect_origin.y + radii.top_left.y});
205
206 //----------------------------------------------------------------------------
207 // Top left arc.
208 //
209 AddRoundedRectTopLeft(rect, radii);
210
211 Close();
212
213 return *this;
214 }
215
216 PathBuilder& PathBuilder::AddRoundedRectTopLeft(Rect rect,
217 RoundingRadii radii) {
218 const auto magic_top_left = radii.top_left * kArcApproximationMagic;
219 const auto corner = rect.GetOrigin();
220 prototype_.AddCubicComponent(
221 {corner.x, corner.y + radii.top_left.y},
222 {corner.x, corner.y + radii.top_left.y - magic_top_left.y},
223 {corner.x + radii.top_left.x - magic_top_left.x, corner.y},
224 {corner.x + radii.top_left.x, corner.y});
225 return *this;
226 }
227
228 PathBuilder& PathBuilder::AddRoundedRectTopRight(Rect rect,
229 RoundingRadii radii) {
230 const auto magic_top_right = radii.top_right * kArcApproximationMagic;
231 const auto corner = rect.GetOrigin() + Point{rect.GetWidth(), 0};
232 prototype_.AddCubicComponent(
233 {corner.x - radii.top_right.x, corner.y},
234 {corner.x - radii.top_right.x + magic_top_right.x, corner.y},
235 {corner.x, corner.y + radii.top_right.y - magic_top_right.y},
236 {corner.x, corner.y + radii.top_right.y});
237 return *this;
238 }
239
240 PathBuilder& PathBuilder::AddRoundedRectBottomRight(Rect rect,
241 RoundingRadii radii) {
242 const auto magic_bottom_right = radii.bottom_right * kArcApproximationMagic;
243 const auto corner = rect.GetOrigin() + rect.GetSize();
244 prototype_.AddCubicComponent(
245 {corner.x, corner.y - radii.bottom_right.y},
246 {corner.x, corner.y - radii.bottom_right.y + magic_bottom_right.y},
247 {corner.x - radii.bottom_right.x + magic_bottom_right.x, corner.y},
248 {corner.x - radii.bottom_right.x, corner.y});
249 return *this;
250 }
251
252 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(Rect rect,
253 RoundingRadii radii) {
254 const auto magic_bottom_left = radii.bottom_left * kArcApproximationMagic;
255 const auto corner = rect.GetOrigin() + Point{0, rect.GetHeight()};
256 prototype_.AddCubicComponent(
257 {corner.x + radii.bottom_left.x, corner.y},
258 {corner.x + radii.bottom_left.x - magic_bottom_left.x, corner.y},
259 {corner.x, corner.y - radii.bottom_left.y + magic_bottom_left.y},
260 {corner.x, corner.y - radii.bottom_left.y});
261 return *this;
262 }
263
264 PathBuilder& PathBuilder::AddArc(const Rect& oval_bounds,
265 Radians start,
266 Radians sweep,
267 bool use_center) {
268 if (sweep.radians < 0) {
269 start.radians += sweep.radians;
270 sweep.radians *= -1;
271 }
272 sweep.radians = std::min(k2Pi, sweep.radians);
273 start.radians = std::fmod(start.radians, k2Pi);
274
275 const Point center = oval_bounds.GetCenter();
276 const Point radius = center - oval_bounds.GetOrigin();
277
278 Vector2 p1_unit(std::cos(start.radians), std::sin(start.radians));
279
280 if (use_center) {
281 MoveTo(center);
282 LineTo(center + p1_unit * radius);
283 } else {
284 MoveTo(center + p1_unit * radius);
285 }
286
287 while (sweep.radians > 0) {
288 Vector2 p2_unit;
289 Scalar quadrant_angle;
290 if (sweep.radians < kPiOver2) {
291 quadrant_angle = sweep.radians;
292 p2_unit = Vector2(std::cos(start.radians + quadrant_angle),
293 std::sin(start.radians + quadrant_angle));
294 } else {
295 quadrant_angle = kPiOver2;
296 p2_unit = Vector2(-p1_unit.y, p1_unit.x);
297 }
298
299 Vector2 arc_cp_lengths =
300 (quadrant_angle / kPiOver2) * kArcApproximationMagic * radius;
301
302 Point p1 = center + p1_unit * radius;
303 Point p2 = center + p2_unit * radius;
304 Point cp1 = p1 + Vector2(-p1_unit.y, p1_unit.x) * arc_cp_lengths;
305 Point cp2 = p2 + Vector2(p2_unit.y, -p2_unit.x) * arc_cp_lengths;
306
307 prototype_.AddCubicComponent(p1, cp1, cp2, p2);
308 current_ = p2;
309
310 start.radians += quadrant_angle;
311 sweep.radians -= quadrant_angle;
312 p1_unit = p2_unit;
313 }
314
315 if (use_center) {
316 Close();
317 }
318
319 return *this;
320 }
321
322 PathBuilder& PathBuilder::AddOval(const Rect& container) {
323 const Point c = container.GetCenter();
324 const Point r = c - container.GetOrigin();
325 const Point m = r * kArcApproximationMagic;
326
327 MoveTo({c.x, c.y - r.y});
328
329 //----------------------------------------------------------------------------
330 // Top right arc.
331 //
332 prototype_.AddCubicComponent({c.x, c.y - r.y}, // p1
333 {c.x + m.x, c.y - r.y}, // cp1
334 {c.x + r.x, c.y - m.y}, // cp2
335 {c.x + r.x, c.y} // p2
336 );
337
338 //----------------------------------------------------------------------------
339 // Bottom right arc.
340 //
341 prototype_.AddCubicComponent({c.x + r.x, c.y}, // p1
342 {c.x + r.x, c.y + m.y}, // cp1
343 {c.x + m.x, c.y + r.y}, // cp2
344 {c.x, c.y + r.y} // p2
345 );
346
347 //----------------------------------------------------------------------------
348 // Bottom left arc.
349 //
350 prototype_.AddCubicComponent({c.x, c.y + r.y}, // p1
351 {c.x - m.x, c.y + r.y}, // cp1
352 {c.x - r.x, c.y + m.y}, // cp2
353 {c.x - r.x, c.y} // p2
354 );
355
356 //----------------------------------------------------------------------------
357 // Top left arc.
358 //
359 prototype_.AddCubicComponent({c.x - r.x, c.y}, // p1
360 {c.x - r.x, c.y - m.y}, // cp1
361 {c.x - m.x, c.y - r.y}, // cp2
362 {c.x, c.y - r.y} // p2
363 );
364
365 Close();
366
367 return *this;
368 }
369
370 PathBuilder& PathBuilder::AddLine(const Point& p1, const Point& p2) {
371 MoveTo(p1);
372 prototype_.AddLinearComponent(p1, p2);
373 return *this;
374 }
375
376 const Path& PathBuilder::GetCurrentPath() const {
377 return prototype_;
378 }
379
380 PathBuilder& PathBuilder::AddPath(const Path& path) {
381 auto linear = [&](size_t index, const LinearPathComponent& l) {
382 prototype_.AddLinearComponent(l.p1, l.p2);
383 };
384 auto quadratic = [&](size_t index, const QuadraticPathComponent& q) {
385 prototype_.AddQuadraticComponent(q.p1, q.cp, q.p2);
386 };
387 auto cubic = [&](size_t index, const CubicPathComponent& c) {
388 prototype_.AddCubicComponent(c.p1, c.cp1, c.cp2, c.p2);
389 };
390 auto move = [&](size_t index, const ContourComponent& m) {
391 prototype_.AddContourComponent(m.destination);
392 };
393 path.EnumerateComponents(linear, quadratic, cubic, move);
394 return *this;
395 }
396
397 PathBuilder& PathBuilder::Shift(Point offset) {
398 prototype_.Shift(offset);
399 return *this;
400 }
401
402 PathBuilder& PathBuilder::SetBounds(Rect bounds) {
403 prototype_.SetBounds(bounds);
404 did_compute_bounds_ = true;
405 return *this;
406 }
407
408 } // namespace impeller
impeller::PathBuilder::AddQuadraticCurve
PathBuilder & AddQuadraticCurve(Point p1, Point cp, Point p2)
Move to point p1, then insert a quadradic curve from p1 to p2 with the control point cp.
Definition: path_builder.cc:101
impeller::LinearPathComponent
Definition: path_component.h:28
impeller::TPoint::y
Type y
Definition: point.h:26
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Path::Clone
Path Clone() const
Deeply clone this path and all data associated with it.
Definition: path.cc:76
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:34
impeller::PathBuilder::SetBounds
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
Definition: path_builder.cc:402
impeller::PathBuilder::CubicCurveTo
PathBuilder & CubicCurveTo(Point controlPoint1, Point controlPoint2, Point point, bool relative=false)
Insert a cubic curve from the curren position to point using the control points controlPoint1 and con...
Definition: path_builder.cc:89
impeller::PathBuilder::AddPath
PathBuilder & AddPath(const Path &path)
Definition: path_builder.cc:380
impeller::PathBuilder
Definition: path_builder.h:14
impeller::Vector2
Point Vector2
Definition: point.h:312
impeller::Convexity
Convexity
Definition: path.h:38
impeller::PathBuilder::RoundingRadii::AreAllZero
bool AreAllZero() const
Definition: path_builder.h:142
impeller::PathBuilder::AddRoundedRect
PathBuilder & AddRoundedRect(Rect rect, RoundingRadii radii)
Definition: path_builder.cc:149
impeller::PathBuilder::HorizontalLineTo
PathBuilder & HorizontalLineTo(Scalar x, bool relative=false)
Definition: path_builder.cc:58
impeller::Radians::radians
Scalar radians
Definition: scalar.h:39
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:225
impeller::PathBuilder::~PathBuilder
~PathBuilder()
impeller::PathBuilder::SetConvexity
PathBuilder & SetConvexity(Convexity value)
Definition: path_builder.cc:84
impeller::PathBuilder::kArcApproximationMagic
constexpr static const Scalar kArcApproximationMagic
Definition: path_builder.h:23
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified when it was constructed.
Definition: rect.h:154
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:116
impeller::PathBuilder::RoundingRadii::bottom_right
Point bottom_right
Definition: path_builder.h:111
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
path_builder.h
impeller::PathBuilder::RoundingRadii
Definition: path_builder.h:107
impeller::TSize< Scalar >
impeller::Point
TPoint< Scalar > Point
Definition: point.h:308
impeller::k2Pi
constexpr float k2Pi
Definition: constants.h:29
impeller::PathBuilder::Shift
PathBuilder & Shift(Point offset)
Transform the existing path segments and contours by the given offset.
Definition: path_builder.cc:397
impeller::Path::EnumerateComponents
void EnumerateComponents(const Applier< LinearPathComponent > &linear_applier, const Applier< QuadraticPathComponent > &quad_applier, const Applier< CubicPathComponent > &cubic_applier, const Applier< ContourComponent > &contour_applier) const
Definition: path.cc:129
impeller::PathBuilder::QuadraticCurveTo
PathBuilder & QuadraticCurveTo(Point controlPoint, Point point, bool relative=false)
Insert a quadradic curve from the current position to point using the control point controlPoint.
Definition: path_builder.cc:74
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:55
impeller::PathBuilder::LineTo
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
Definition: path_builder.cc:51
impeller::PathBuilder::AddCubicCurve
PathBuilder & AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2)
Move to point p1, then insert a cubic curve from p1 to p2 with control points cp1 and cp2.
Definition: path_builder.cc:107
impeller::PathBuilder::RoundingRadii::top_left
Point top_left
Definition: path_builder.h:108
impeller::Radians
Definition: scalar.h:38
impeller::FillType
FillType
Definition: path.h:30
impeller::PathBuilder::AddLine
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Definition: path_builder.cc:370
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:21
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:488
impeller::TSize::width
Type width
Definition: size.h:22
impeller::TPoint::x
Type x
Definition: point.h:25
impeller::PathBuilder::PathBuilder
PathBuilder()
impeller::CubicPathComponent
Definition: path_component.h:94
impeller::PathBuilder::Reserve
void Reserve(size_t point_size, size_t verb_size)
Reserve [point_size] points and [verb_size] verbs in the underlying path buffer.
Definition: path_builder.cc:32
impeller::PathBuilder::GetCurrentPath
const Path & GetCurrentPath() const
Definition: path_builder.cc:376
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle as specified when it was constructed and which may be negative in e...
Definition: rect.h:159
impeller::PathBuilder::Close
PathBuilder & Close()
Definition: path_builder.cc:44
impeller::PathBuilder::CopyPath
Path CopyPath(FillType fill=FillType::kNonZero) const
Definition: path_builder.cc:15
impeller::PathBuilder::RoundingRadii::top_right
Point top_right
Definition: path_builder.h:110
impeller::TPoint< Scalar >
impeller::PathBuilder::MoveTo
PathBuilder & MoveTo(Point point, bool relative=false)
Definition: path_builder.cc:37
impeller::PathBuilder::RoundingRadii::bottom_left
Point bottom_left
Definition: path_builder.h:109
impeller::PathBuilder::VerticalLineTo
PathBuilder & VerticalLineTo(Scalar y, bool relative=false)
Definition: path_builder.cc:66
impeller::PathBuilder::AddCircle
PathBuilder & AddCircle(const Point &center, Scalar radius)
Definition: path_builder.cc:134
impeller::TSize::height
Type height
Definition: size.h:23
impeller::PathBuilder::AddOval
PathBuilder & AddOval(const Rect &rect)
Definition: path_builder.cc:322
impeller::ContourComponent
Definition: path_component.h:146
impeller
Definition: aiks_context.cc:10
impeller::QuadraticPathComponent
Definition: path_component.h:52
impeller::TRect< Scalar >
impeller::PathBuilder::AddArc
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
Definition: path_builder.cc:264