Interpolate between two SkPath

207 views
Skip to first unread message

Sherlock Doyle

unread,
Dec 2, 2021, 2:05:03 PM12/2/21
to skia-discuss
I understand that you can interpolate between two SkPath with an equal number of points and the same arrangement of verbs and weights.

But how would one go about interpolating between any two general SkPath, with possibly different numbers of points, verbs, and weights?

Brian Osman

unread,
Dec 2, 2021, 2:14:33 PM12/2/21
to skia-d...@googlegroups.com
Answering this fully requires a heuristic for how you want the interpolation to behave. There are a few pieces of a solution I can propose (like just brute-force linearizing both paths to produce uniformly spaced line segments, then making the lists of segments equal length by linearly filtering the shorter list to match the longer list), but that leave giant open questions about paths with different numbers of contours. What does it mean to interpolate a path containing a circle to a path containing two circles? Or a single line segment to a stroked version of that line segment? The "obviously correct" answer to that last question isn't something that's going to fall out naturally from any algorithm you write - it's a tuned special case, but it's also true that any other answer is going to look strange and wrong.

On Thu, Dec 2, 2021 at 2:05 PM Sherlock Doyle <sherlock...@gmail.com> wrote:
I understand that you can interpolate between two SkPath with an equal number of points and the same arrangement of verbs and weights.

But how would one go about interpolating between any two general SkPath, with possibly different numbers of points, verbs, and weights?

--
You received this message because you are subscribed to the Google Groups "skia-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to skia-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/skia-discuss/73f38420-21cf-4d43-934d-c4a7975dd1c2n%40googlegroups.com.

Sherlock Doyle

unread,
Dec 3, 2021, 4:00:59 AM12/3/21
to skia-discuss
For the following make an assumption that both the path contains a single contour. What's the skia way to linearize a path? How can I get n equidistant points on a path?

One approach I can think of is:
pathMeasure = PathMeasure(path)
d = pathMeasure.getLength()
for i = 0..n:
    pos = position from pathMeasure.getPosTan(distance=d/n*i)

However, this seems kinda counter-intuitive to me, having to loop around manually. This might also be slow because possibly getPosTan is unable to reuse some of the internal variables. Is there a better way?

Brian Osman

unread,
Dec 3, 2021, 8:54:08 AM12/3/21
to skia-d...@googlegroups.com
No, I think that's the easiest approach (it's what I was going to suggest). It may not be entirely optimal, but I don't think there's any code that will do a better job.

Sherlock Doyle

unread,
Dec 3, 2021, 1:31:12 PM12/3/21
to skia-discuss
Take a look at cairo_copy_path_flat. Its functionality, in short, is: It returns the path as a list of line segments. Original lines (line_to) are kept as is, however the curves (cubic_to) are approximated with piecewise-linear approximations. In other words, it doesn't subdivide lines, but only curves.

ls something similar possible with skia?

Sherlock Doyle

unread,
Dec 5, 2021, 11:40:10 AM12/5/21
to skia-discuss
For people who visit this thread in the future, here's a different (more complicated) approach for animating between two paths. Note that, at the time of writing this, I haven't tested this, so look for bugs. If you find something better or have any suggestions, please keep extending this thread.

The problem with linearizing a path is, you don't know the value of n (see above). Whatever value you choose, with enough zoom (scale) you'll be able to see the angles, the smoothness is lost. You also need to control too many points, depending on your value of n.

Instead of getting a bunch of line segments, convert each verb to a cubic-bezier (find out how, for instance, using ConvertConicToQuads, etc). Curves can represent both lines and curves, this will preserve curvy-ness under zoom. Here's a simplified algorithm.
  1. Convert all verbs to cubics.
  2. If the number of verbs in both paths doesn't match, subdivide curves of the smaller path. Here's a sample algorithm.
    1. Convert the path to a linked list with each curve in a separate node.
    2. Use a max heap to keep track of the nodes to the length of the curves.
    3. Pop the top curve (node) in the heap, split it (https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm), push both the split curve.
  3. Now interpolate with equal verbs!
Suggestions welcome.
Reply all
Reply to author
Forward
0 new messages