BezPath

from kurbopy import BezPath

bez = BezPath()
bez.move_to(Point(100, 100))
bez.line_to(Point(100, 200))
bez.quad_to(Point(200, 200), Point(200, 100))
class kurbopy.BezPath

A Bézier path.

These docs assume basic familiarity with Bézier curves; for an introduction, see Pomax’s wonderful A Primer on Bézier Curves.

This path can contain lines, quadratics ([QuadBez]) and cubics ([CubicBez]), and may contain multiple subpaths.

Elements and Segments

A Bézier path can be represented in terms of either ‘elements’ ([PathEl]) or ‘segments’ ([PathSeg]). Elements map closely to how Béziers are generally used in PostScript-style drawing APIs; they can be thought of as instructions for drawing the path. Segments more directly describe the path itself, with each segment being an independent line or curve.

These different representations are useful in different contexts. For tasks like drawing, elements are a natural fit, but when doing hit-testing or subdividing, we need to have access to the segments.

from kurbopy import BezPath, Rect, Shape, Vec2, Point
accuracy = 0.1
rect = Rect(Point(0, 0), Point(10, 10))
path1 = rect.to_path(accuracy)

# extend a path with another path:
path = rect.to_path(accuracy)
shifted_rect = rect + Vec2(5.0, 10.0)
path.extend(shifted_rect.to_path(accuracy))

Advanced functionality

In addition to the basic API, there are several useful pieces of advanced functionality available on BezPath:

  • ```flatten```_ does Bézier flattening, converting a curve to a series of line segments

  • ```intersections```_ computes intersections of a path with a line, useful for things like subdividing

area()

Compute the signed area under the curve.

For a closed path, the signed area of the path is the sum of signed areas of the segments. This is a variant of the “shoelace formula.” See: <https://github.com/Pomax/bezierinfo/issues/44> and <http://ich.deanmcnamee.com/graphics/2016/03/30/CurveArea.html>

This can be computed exactly for Béziers thanks to Green’s theorem, and also for simple curves such as circular arcs. For more exotic curves, it’s probably best to subdivide to cubics. We leave that to the caller, which is why we don’t give an accuracy param here.

bounding_box()

The smallest rectangle that encloses the shape.

close_path()

Push a “close path” element onto the path.

curve_to(pt1, pt2, pt3)

Push a “curve to” element onto the path.

flatten(tolerance)

Flatten the path, returning a list of points.

fromDrawable(*penArgs, **penKwargs)

Returns an array of BezPath from any object conforming to the pen protocol.

intersections(line)

Computes the intersections with a line as a list of Point objects.

Note that this method is not in original kurbo

intersects(other)

Returns true if the two BezPaths intersect

Note that this method is not in original kurbo

is_empty()

Returns true if the path contains no segments.

is_finite()

Is this path finite?

is_nan()

Is this path NaN?

line_to(pt)

Push a “line to” element onto the path.

min_distance(other)

Computes the minimum distance between this BezPath and another.

Note that this method is not in original kurbo

move_to(pt)

Push a “move to” element onto the path.

perimeter(accuracy)

Total length of perimeter.

plot(ax, **kwargs)

Plot the path on a Matplot subplot which you supply

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
path.plot(ax)
quad_to(pt1, pt2)

Push a “quad to” element onto the path.

scale_path(scale_factor)
to_matplot()
to_svg()

Convert the path to an SVG path string representation.

The current implementation doesn’t take any special care to produce a short string (reducing precision, using relative movement).

winding(pt)

The winding number of a point.

This method only produces meaningful results with closed shapes.

The sign of the winding number is consistent with that of area, meaning it is +1 when the point is inside a positive area shape and -1 when it is inside a negative area shape. Of course, greater magnitude values are also possible when the shape is more complex.