| Flutter Impeller |

Classes | Public Types | Public Member Functions | Friends | List of all members
impeller::Path Class Reference

Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments. These segments may be broken up by move commands, which are effectively linear commands that pick up the pen rather than continuing to draw. More...

`#include <path.h>`

## Classes
struct | Polyline
struct | PolylineContour

## Public Types
enum | ComponentType { ComponentType::kLinear, ComponentType::kQuadratic, ComponentType::kCubic, ComponentType::kContour }
template<class T >
using | Applier = std::function< void(size_t index, const T &component)>

## Public Member Functions
| Path ()
| ~Path ()
size_t | GetComponentCount (std::optional< ComponentType > type={}) const
FillType | GetFillType () const
bool | IsConvex () const
void | EnumerateComponents (const Applier< LinearPathComponent > &linear_applier, const Applier< QuadraticPathComponent > &quad_applier, const Applier< CubicPathComponent > &cubic_applier, const Applier< ContourComponent > &contour_applier) const
bool | GetLinearComponentAtIndex (size_t index, LinearPathComponent &linear) const
bool | GetQuadraticComponentAtIndex (size_t index, QuadraticPathComponent &quadratic) const
bool | GetCubicComponentAtIndex (size_t index, CubicPathComponent &cubic) const
bool | GetContourComponentAtIndex (size_t index, ContourComponent &contour) const
Polyline | CreatePolyline (Scalar scale) const
std::optional< Rect > | GetBoundingBox () const
std::optional< Rect > | GetTransformedBoundingBox (const Matrix &transform) const
std::optional< std::pair< Point, Point > > | GetMinMaxCoveragePoints () const

## Friends
class | PathBuilder

## Detailed Description

Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments. These segments may be broken up by move commands, which are effectively linear commands that pick up the pen rather than continuing to draw.

All shapes supported by Impeller are paths either directly or via approximation (in the case of circles).

Paths are externally immutable once created, Creating paths must be done using a path builder.

Definition at line 54 of file path.h.

## Member Typedef Documentation

## ◆ Applier

template<class T >

using impeller::Path::Applier = std::function<void(size_t index, const T& component)>

Definition at line 103 of file path.h.

## Member Enumeration Documentation

## ◆ ComponentType

enum impeller::Path::ComponentType
| strong

Enumerator
kLinear |
kQuadratic |
kCubic |
kContour |

Definition at line 56 of file path.h.

56 {
57 kLinear,
58 kQuadratic,
59 kCubic,
60 kContour,
61 };

## Constructor & Destructor Documentation

## ◆ Path()

impeller::Path::Path | ( |  | ) |

Definition at line 14 of file path.cc.

14 {
15 AddContourComponent({});
16 };

## ◆ ~Path()

impeller::Path::~Path | ( |  | ) |
| default

## Member Function Documentation

## ◆ CreatePolyline()

Path::Polyline impeller::Path::CreatePolyline | ( | Scalar | scale | ) | const

Callers must provide the scale factor for how this path will be transformed.

It is suitable to use the max basis length of the matrix used to transform the path. If the provided scale is 0, curves will revert to lines.

Definition at line 272 of file path.cc.

272 {
273 Polyline polyline;
274
275 std::optional<Point> previous_contour_point;
276 auto collect_points = [&polyline, &previous_contour_point](
277 const std::vector<Point>& collection) {
278 if (collection.empty()) {
279 return;
280 }
281
282 for (const auto& point : collection) {
283 if (previous_contour_point.has_value() &&
284 previous_contour_point.value() == point) {
285 // Skip over duplicate points in the same contour.
286 continue;
287 }
288 previous_contour_point = point;
289 polyline.points.push_back(point);
290 }
291 };
292
293 auto get_path_component = [this](size_t component_i) -> PathComponentVariant {
294 if (component_i >= components_.size()) {
295 return std::monostate{};
296 }
297 const auto& component = components_[component_i];
298 switch (component.type) {
299 case ComponentType::kLinear:
300 return &linears_[component.index];
301 case ComponentType::kQuadratic:
302 return &quads_[component.index];
303 case ComponentType::kCubic:
304 return &cubics_[component.index];
305 case ComponentType::kContour:
306 return std::monostate{};
307 }
308 };
309
310 auto compute_contour_start_direction =
311 [&get_path_component](size_t current_path_component_index) {
312 size_t next_component_index = current_path_component_index + 1;
313 while (!std::holds_alternative<std::monostate>(
314 get_path_component(next_component_index))) {
315 auto next_component = get_path_component(next_component_index);
316 auto maybe_vector =
317 std::visit(PathComponentStartDirectionVisitor(), next_component);
318 if (maybe_vector.has_value()) {
319 return maybe_vector.value();
320 } else {
321 next_component_index++;
322 }
323 }
324 return Vector2(0, -1);
325 };
326
327 std::optional<size_t> previous_path_component_index;
328 auto end_contour = [&polyline, &previous_path_component_index,
329 &get_path_component]() {
330 // Whenever a contour has ended, extract the exact end direction from the
331 // last component.
332 if (polyline.contours.empty()) {
333 return;
334 }
335
336 if (!previous_path_component_index.has_value()) {
337 return;
338 }
339
340 auto& contour = polyline.contours.back();
341 contour.end_direction = Vector2(0, 1);
342
343 size_t previous_index = previous_path_component_index.value();
344 while (!std::holds_alternative<std::monostate>(
345 get_path_component(previous_index))) {
346 auto previous_component = get_path_component(previous_index);
347 auto maybe_vector =
348 std::visit(PathComponentEndDirectionVisitor(), previous_component);
349 if (maybe_vector.has_value()) {
350 contour.end_direction = maybe_vector.value();
351 break;
352 } else {
353 if (previous_index == 0) {
354 break;
355 }
356 previous_index--;
357 }
358 }
359 };
360
361 for (size_t component_i = 0; component_i < components_.size();
362 component_i++) {
363 const auto& component = components_[component_i];
364 switch (component.type) {
365 case ComponentType::kLinear:
366 collect_points(linears_[component.index].CreatePolyline());
367 previous_path_component_index = component_i;
368 break;
369 case ComponentType::kQuadratic:
370 collect_points(quads_[component.index].CreatePolyline(scale));
371 previous_path_component_index = component_i;
372 break;
373 case ComponentType::kCubic:
374 collect_points(cubics_[component.index].CreatePolyline(scale));
375 previous_path_component_index = component_i;
376 break;
377 case ComponentType::kContour:
378 if (component_i == components_.size() - 1) {
379 // If the last component is a contour, that means it's an empty
380 // contour, so skip it.
381 continue;
382 }
383 end_contour();
384
385 Vector2 start_direction = compute_contour_start_direction(component_i);
386 const auto& contour = contours_[component.index];
387 polyline.contours.push_back({.start_index = polyline.points.size(),
388 .is_closed = contour.is_closed,
389 .start_direction = start_direction});
390 previous_contour_point = std::nullopt;
391 collect_points({contour.destination});
392 break;
393 }
394 end_contour();
395 }
396 return polyline;
397 }

References impeller::Path::Polyline::contours, kContour, kCubic, kLinear, kQuadratic, and impeller::Path::Polyline::points.

Referenced by impeller::Tessellate(), and impeller::testing::TEST().

## ◆ EnumerateComponents()

void impeller::Path::EnumerateComponents | ( | const Applier< LinearPathComponent > & | linear_applier,
|  | const Applier< QuadraticPathComponent > & | quad_applier,
|  | const Applier< CubicPathComponent > & | cubic_applier,
|  | const Applier< ContourComponent > & | contour_applier
| ) |  | const

Definition at line 125 of file path.cc.

129 {
130 size_t currentIndex = 0;
131 for (const auto& component : components_) {
132 switch (component.type) {
133 case ComponentType::kLinear:
134 if (linear_applier) {
135 linear_applier(currentIndex, linears_[component.index]);
136 }
137 break;
138 case ComponentType::kQuadratic:
139 if (quad_applier) {
140 quad_applier(currentIndex, quads_[component.index]);
141 }
142 break;
143 case ComponentType::kCubic:
144 if (cubic_applier) {
145 cubic_applier(currentIndex, cubics_[component.index]);
146 }
147 break;
148 case ComponentType::kContour:
149 if (contour_applier) {
150 contour_applier(currentIndex, contours_[component.index]);
151 }
152 break;
153 }
154 currentIndex++;
155 }
156 }

References kContour, kCubic, kLinear, and kQuadratic.

Referenced by impeller::PathBuilder::AddPath(), and impeller::ComputeTessellator::Tessellate().

## ◆ GetBoundingBox()

std::optional< Rect > impeller::Path::GetBoundingBox | ( |  | ) | const

Definition at line 399 of file path.cc.

399 {
400 return computed_bounds_;
401 }

Referenced by impeller::Canvas::ClipPath(), GetTransformedBoundingBox(), and impeller::testing::TEST().

## ◆ GetComponentCount()

size_t impeller::Path::GetComponentCount | ( | std::optional< ComponentType > | type = `{}` | ) | const

Definition at line 32 of file path.cc.

32 {
33 if (type.has_value()) {
34 switch (type.value()) {
35 case ComponentType::kLinear:
36 return linears_.size();
37 case ComponentType::kQuadratic:
38 return quads_.size();
39 case ComponentType::kCubic:
40 return cubics_.size();
41 case ComponentType::kContour:
42 return contours_.size();
43 }
44 }
45 return components_.size();
46 }

References kContour, kCubic, kLinear, and kQuadratic.

Referenced by impeller::ComputeTessellator::Tessellate().

## ◆ GetContourComponentAtIndex()

bool impeller::Path::GetContourComponentAtIndex | ( | size_t | index,
|  | ContourComponent & | contour
| ) |  | const

Definition at line 201 of file path.cc.

202 {
203 if (index >= components_.size()) {
204 return false;
205 }
206
207 if (components_[index].type != ComponentType::kContour) {
208 return false;
209 }
210
211 move = contours_[components_[index].index];
212 return true;
213 }

References kContour.

Referenced by impeller::testing::TEST().

## ◆ GetCubicComponentAtIndex()

bool impeller::Path::GetCubicComponentAtIndex | ( | size_t | index,
|  | CubicPathComponent & | cubic
| ) |  | const

Definition at line 187 of file path.cc.

188 {
189 if (index >= components_.size()) {
190 return false;
191 }
192
193 if (components_[index].type != ComponentType::kCubic) {
194 return false;
195 }
196
197 cubic = cubics_[components_[index].index];
198 return true;
199 }

References kCubic.

## ◆ GetFillType()

FillType impeller::Path::GetFillType | ( |  | ) | const

Definition at line 52 of file path.cc.

52 {
53 return fill_;
54 }

## ◆ GetLinearComponentAtIndex()

bool impeller::Path::GetLinearComponentAtIndex | ( | size_t | index,
|  | LinearPathComponent & | linear
| ) |  | const

Definition at line 158 of file path.cc.

159 {
160 if (index >= components_.size()) {
161 return false;
162 }
163
164 if (components_[index].type != ComponentType::kLinear) {
165 return false;
166 }
167
168 linear = linears_[components_[index].index];
169 return true;
170 }

References kLinear.

## ◆ GetMinMaxCoveragePoints()

std::optional< std::pair< Point, Point > > impeller::Path::GetMinMaxCoveragePoints | ( |  | ) | const

Definition at line 424 of file path.cc.

424 {
425 if (linears_.empty() && quads_.empty() && cubics_.empty()) {
426 return std::nullopt;
427 }
428
429 std::optional<Point> min, max;
430
431 auto clamp = [&min, &max](const Point& point) {
432 if (min.has_value()) {
433 min = min->Min(point);
434 } else {
435 min = point;
436 }
437
438 if (max.has_value()) {
439 max = max->Max(point);
440 } else {
441 max = point;
442 }
443 };
444
445 for (const auto& linear : linears_) {
446 clamp(linear.p1);
447 clamp(linear.p2);
448 }
449
450 for (const auto& quad : quads_) {
451 for (const Point& point : quad.Extrema()) {
452 clamp(point);
453 }
454 }
455
456 for (const auto& cubic : cubics_) {
457 for (const Point& point : cubic.Extrema()) {
458 clamp(point);
459 }
460 }
461
462 if (!min.has_value() || !max.has_value()) {
463 return std::nullopt;
464 }
465
466 return std::make_pair(min.value(), max.value());
467 }

References impeller::LinearPathComponent::p1, and impeller::LinearPathComponent::p2.

## ◆ GetQuadraticComponentAtIndex()

bool impeller::Path::GetQuadraticComponentAtIndex | ( | size_t | index,
|  | QuadraticPathComponent & | quadratic
| ) |  | const

Definition at line 172 of file path.cc.

174 {
175 if (index >= components_.size()) {
176 return false;
177 }
178
179 if (components_[index].type != ComponentType::kQuadratic) {
180 return false;
181 }
182
183 quadratic = quads_[components_[index].index];
184 return true;
185 }

References kQuadratic.

## ◆ GetTransformedBoundingBox()

std::optional< Rect > impeller::Path::GetTransformedBoundingBox | ( | const Matrix & | transform | ) | const

Definition at line 415 of file path.cc.

416 {
417 auto bounds = GetBoundingBox();
418 if (!bounds.has_value()) {
419 return std::nullopt;
420 }
421 return bounds->TransformBounds(transform);
422 }

References GetBoundingBox().

## ◆ IsConvex()

bool impeller::Path::IsConvex | ( |  | ) | const

Definition at line 56 of file path.cc.

56 {
57 return convexity_ == Convexity::kConvex;
58 }

References impeller::kConvex.

## Friends And Related Function Documentation

## ◆ PathBuilder

friend class PathBuilder
| friend

Definition at line 135 of file path.h.

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

- impeller/geometry/path.h
- impeller/geometry/path.cc

impeller::Path::ComponentType::kLinear
@ kLinear
impeller::Path::ComponentType::kCubic
@ kCubic
impeller::Vector2
Point Vector2
Definition: point.h:310
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:399
impeller::Path::ComponentType::kQuadratic
@ kQuadratic
impeller::Point
TPoint< Scalar > Point
Definition: point.h:306
impeller::MinMagFilter::kLinear
@ kLinear
impeller::PathComponentVariant
std::variant< std::monostate, const LinearPathComponent *, const QuadraticPathComponent *, const CubicPathComponent * > PathComponentVariant
Definition: path_component.h:154
impeller::Convexity::kConvex
@ kConvex
impeller::Path::ComponentType::kContour
@ kContour