16 AddContourComponent({});
22 prototype_.fill = fill;
23 prototype_.single_contour =
24 current_contour_location_ == 0u ||
25 (contour_count_ == 2 &&
27 return Path(prototype_);
31 prototype_.fill = fill;
33 prototype_.single_contour =
34 current_contour_location_ == 0u ||
35 (contour_count_ == 2 &&
37 current_contour_location_ = 0u;
39 return Path(std::move(prototype_));
43 prototype_.points.reserve(point_size);
44 prototype_.components.reserve(verb_size);
48 current_ = relative ? current_ + point : point;
49 subpath_start_ = current_;
50 AddContourComponent(current_);
58 if (subpath_start_ != current_) {
61 SetContourClosed(
true);
62 AddContourComponent(current_);
67 point = relative ? current_ + point : point;
68 AddLinearComponent(current_, point);
76 AddLinearComponent(current_, endpoint);
83 relative ?
Point{current_.
x, current_.
y + y} :
Point{current_.
x, y};
84 AddLinearComponent(current_, endpoint);
92 point = relative ? current_ + point : point;
93 controlPoint = relative ? current_ + controlPoint : controlPoint;
94 AddQuadraticComponent(current_, controlPoint, point);
103 point = relative ? current_ + point : point;
104 controlPoint = relative ? current_ + controlPoint : controlPoint;
105 AddConicComponent(current_, controlPoint, point, weight);
111 prototype_.convexity =
value;
119 controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
120 controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
121 point = relative ? current_ + point : point;
122 AddCubicComponent(current_, controlPoint1, controlPoint2, point);
131 AddQuadraticComponent(p1, cp, p2);
140 AddConicComponent(p1, cp, p2, weight);
149 AddCubicComponent(p1, cp1, cp2, p2);
158 auto bl = origin +
Point{0.0, size.height};
159 auto br = origin + size;
160 auto tr = origin +
Point{size.width, 0.0};
178 if (radii.AreAllCornersEmpty()) {
182 auto rect_origin = rect.GetOrigin();
183 auto rect_size = rect.GetSize();
185 current_ = rect_origin +
Point{radii.top_left.width, 0.0};
187 MoveTo({rect_origin.x + radii.top_left.width, rect_origin.y});
192 AddLinearComponentIfNeeded(
193 {rect_origin.x + radii.top_left.width, rect_origin.y},
194 {rect_origin.x + rect_size.width - radii.top_right.width, rect_origin.y});
199 AddRoundedRectTopRight(rect, radii);
204 AddLinearComponentIfNeeded(
205 {rect_origin.x + rect_size.width, rect_origin.y + radii.top_right.height},
206 {rect_origin.x + rect_size.width,
207 rect_origin.y + rect_size.height - radii.bottom_right.height});
212 AddRoundedRectBottomRight(rect, radii);
217 AddLinearComponentIfNeeded(
218 {rect_origin.x + rect_size.width - radii.bottom_right.width,
219 rect_origin.y + rect_size.height},
220 {rect_origin.x + radii.bottom_left.width,
221 rect_origin.y + rect_size.height});
226 AddRoundedRectBottomLeft(rect, radii);
231 AddLinearComponentIfNeeded(
233 rect_origin.y + rect_size.height - radii.bottom_left.height},
234 {rect_origin.x, rect_origin.y + radii.top_left.height});
239 AddRoundedRectTopLeft(rect, radii);
249 }
else if (rse.
IsOval()) {
265 {corner.x, corner.y + radii.
top_left.
height - magic_top_left.height},
266 {corner.x + radii.
top_left.
width - magic_top_left.width, corner.y},
271 PathBuilder& PathBuilder::AddRoundedRectTopRight(
Rect rect,
272 RoundingRadii radii) {
274 const auto corner = rect.GetOrigin() +
Point{rect.GetWidth(), 0};
276 {corner.x - radii.top_right.width, corner.y},
277 {corner.x - radii.top_right.width + magic_top_right.width, corner.y},
278 {corner.x, corner.y + radii.top_right.height - magic_top_right.height},
279 {corner.x, corner.y + radii.top_right.height});
283 PathBuilder& PathBuilder::AddRoundedRectBottomRight(
Rect rect,
284 RoundingRadii radii) {
286 const auto corner = rect.GetOrigin() + rect.GetSize();
288 {corner.x, corner.y - radii.bottom_right.height},
290 corner.y - radii.bottom_right.height + magic_bottom_right.height},
291 {corner.x - radii.bottom_right.width + magic_bottom_right.width,
293 {corner.x - radii.bottom_right.width, corner.y});
297 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(
Rect rect,
298 RoundingRadii radii) {
300 const auto corner = rect.GetOrigin() +
Point{0, rect.GetHeight()};
302 {corner.x + radii.bottom_left.width, corner.y},
303 {corner.x + radii.bottom_left.width - magic_bottom_left.width, corner.y},
305 corner.y - radii.bottom_left.height + magic_bottom_left.height},
306 {corner.x, corner.y - radii.bottom_left.height});
310 void PathBuilder::AddContourComponent(
const Point& destination,
312 auto& components = prototype_.components;
313 auto& points = prototype_.points;
314 auto closed = is_closed ?
Point{0, 0} :
Point{1, 1};
315 if (components.size() > 0 &&
318 points[current_contour_location_] = destination;
319 points[current_contour_location_ + 1] = closed;
321 current_contour_location_ = points.size();
322 points.push_back(destination);
323 points.push_back(closed);
327 prototype_.bounds.reset();
330 void PathBuilder::AddLinearComponentIfNeeded(
const Point& p1,
const Point& p2) {
335 AddLinearComponent(p1, p2);
338 void PathBuilder::AddLinearComponent(
const Point& p1,
const Point& p2) {
339 auto& points = prototype_.points;
340 points.push_back(p1);
341 points.push_back(p2);
343 prototype_.bounds.reset();
346 void PathBuilder::AddQuadraticComponent(
const Point& p1,
349 auto& points = prototype_.points;
350 points.push_back(p1);
351 points.push_back(cp);
352 points.push_back(p2);
354 prototype_.bounds.reset();
357 void PathBuilder::AddConicComponent(
const Point& p1,
361 if (!std::isfinite(weight)) {
362 AddLinearComponent(p1, cp);
363 AddLinearComponent(cp, p2);
364 }
else if (weight <= 0) {
365 AddLinearComponent(p1, p2);
366 }
else if (weight == 1) {
367 AddQuadraticComponent(p1, cp, p2);
369 auto& points = prototype_.points;
370 points.push_back(p1);
371 points.push_back(cp);
372 points.push_back(p2);
373 points.emplace_back(weight, weight);
375 prototype_.bounds.reset();
379 void PathBuilder::AddCubicComponent(
const Point& p1,
383 auto& points = prototype_.points;
384 points.push_back(p1);
385 points.push_back(cp1);
386 points.push_back(cp2);
387 points.push_back(p2);
389 prototype_.bounds.reset();
392 void PathBuilder::SetContourClosed(
bool is_closed) {
393 prototype_.points[current_contour_location_ + 1] =
415 LineTo(center + p1_unit * radius);
417 MoveTo(center + p1_unit * radius);
424 quadrant_angle = sweep.
radians;
426 std::sin(start.
radians + quadrant_angle));
429 p2_unit =
Vector2(-p1_unit.
y, p1_unit.
x);
435 Point p1 = center + p1_unit * radius;
436 Point p2 = center + p2_unit * radius;
440 AddCubicComponent(p1, cp1, cp2, p2);
443 start.
radians += quadrant_angle;
444 sweep.
radians -= quadrant_angle;
465 AddCubicComponent({c.
x, c.
y - r.
y},
466 {c.
x + m.
x, c.
y - r.
y},
467 {c.
x + r.
x, c.
y - m.
y},
474 AddCubicComponent({c.
x + r.
x, c.
y},
475 {c.
x + r.
x, c.
y + m.
y},
476 {c.
x + m.
x, c.
y + r.
y},
483 AddCubicComponent({c.
x, c.
y + r.
y},
484 {c.
x - m.
x, c.
y + r.
y},
485 {c.
x - r.
x, c.
y + m.
y},
492 AddCubicComponent({c.
x - r.
x, c.
y},
493 {c.
x - r.
x, c.
y - m.
y},
494 {c.
x - m.
x, c.
y - r.
y},
505 AddLinearComponent(p1, p2);
510 auto& points = prototype_.points;
511 auto& components = prototype_.components;
512 size_t source_offset = points.size();
514 points.insert(points.end(), path.data_->points.begin(),
515 path.data_->points.end());
516 components.insert(components.end(), path.data_->components.begin(),
517 path.data_->components.end());
519 for (
auto component : path.data_->components) {
521 current_contour_location_ = source_offset;
530 auto& points = prototype_.points;
531 size_t storage_offset = 0u;
532 for (
const auto& component : prototype_.components) {
572 prototype_.bounds.reset();
577 prototype_.bounds = bounds;
581 void PathBuilder::UpdateBounds() {
582 if (!prototype_.bounds.has_value()) {
583 auto min_max = GetMinMaxCoveragePoints();
584 if (!min_max.has_value()) {
585 prototype_.bounds.reset();
588 auto min = min_max->first;
589 auto max = min_max->second;
590 const auto difference = max - min;
596 std::optional<std::pair<Point, Point>> PathBuilder::GetMinMaxCoveragePoints()
598 auto& points = prototype_.points;
600 if (points.empty()) {
604 std::optional<Point> min, max;
606 auto clamp = [&min, &max](
const Point& point) {
607 if (min.has_value()) {
608 min = min->Min(point);
613 if (max.has_value()) {
614 max = max->Max(point);
620 size_t storage_offset = 0u;
621 for (
const auto& component : prototype_.components) {
624 auto* linear =
reinterpret_cast<const LinearPathComponent*
>(
625 &points[storage_offset]);
631 for (
const auto& extrema :
632 reinterpret_cast<const QuadraticPathComponent*
>(
633 &points[storage_offset])
639 for (
const auto& extrema :
reinterpret_cast<const ConicPathComponent*
>(
640 &points[storage_offset])
646 for (
const auto& extrema :
reinterpret_cast<const CubicPathComponent*
>(
647 &points[storage_offset])
658 if (!min.has_value() || !max.has_value()) {
662 return std::make_pair(min.value(), max.value());
Path TakePath(FillType fill=FillType::kNonZero)
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
PathBuilder & AddRoundRect(RoundRect rect)
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
PathBuilder & MoveTo(Point point, bool relative=false)
PathBuilder & AddRect(const Rect &rect)
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
void Reserve(size_t point_size, size_t verb_size)
Reserve [point_size] points and [verb_size] verbs in the underlying path buffer.
PathBuilder & AddCubicCurve(const Point &p1, const Point &cp1, const Point &cp2, const Point &p2)
Move to point p1, then insert a cubic curve from p1 to p2 with control points cp1 and cp2.
PathBuilder & AddOval(const Rect &rect)
PathBuilder & AddCircle(const Point ¢er, Scalar radius)
PathBuilder & AddPath(const Path &path)
PathBuilder & AddConicCurve(const Point &p1, const Point &cp, const Point &p2, Scalar weight)
Move to point p1, then insert a conic curve from p1 to p2 with the control point cp and weight weight...
Path CopyPath(FillType fill=FillType::kNonZero)
PathBuilder & VerticalLineTo(Scalar y, bool relative=false)
PathBuilder & Shift(Point offset)
Transform the existing path segments and contours by the given offset.
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
constexpr static const Scalar kArcApproximationMagic
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...
PathBuilder & ConicCurveTo(Point controlPoint, Point point, Scalar weight, bool relative=false)
Insert a conic curve from the current position to point using the control point controlPoint and the ...
PathBuilder & AddQuadraticCurve(const Point &p1, const Point &cp, const Point &p2)
Move to point p1, then insert a quadradic curve from p1 to p2 with the control point cp.
PathBuilder & HorizontalLineTo(Scalar x, bool relative=false)
PathBuilder & AddRoundSuperellipse(RoundSuperellipse rse)
PathBuilder & SetConvexity(Convexity value)
PathBuilder & QuadraticCurveTo(Point controlPoint, Point point, bool relative=false)
Insert a quadradic curve from the current position to point using the control point controlPoint.
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
static constexpr size_t VerbToOffset(Path::ComponentType verb)
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
constexpr const RoundingRadii & GetRadii() const
constexpr bool IsOval() const
constexpr bool IsRect() const
constexpr const Rect & GetBounds() const
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
void AddToPath(PathBuilder &path) const
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
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...
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr Point GetCenter() const
Get the center point as a |Point|.