mathandy / svgpathtools

A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves.
MIT License
558 stars 142 forks source link

Question: is it possible to split segments? #104

Closed thednp closed 4 years ago

thednp commented 4 years ago

Hi there.

I'm working on a new component for morphing SVGs and was wandering if your script can split segments somehow? Let me explain.

I am currently using some modified code from Raphael.js called path2curve which converts path commands to cubic-bezier, then replicates some of them in order to make both startShape and endShape have same amount of cubic-bezier points, but that's not always best in terms of visuals.

I need something that can normalize path commands by splitting long segments (in terms of length) into 2/more segments so that they're evenly distributed along both paths, and in the end have same number of points in both shapes.

Is this possible with your library?

mathandy commented 4 years ago

Hi @thednp! Here's an example

from svgpathtools import parse_path, Path, disvg

# make an example path with a couple segments
p = parse_path("M 151,395 C 407,485 726.17662,160 634,339 L500,500")

# find the halfway point (and which segment it happens in)
half_way_point = p.ilength(p.length() / 2)
segment_index, segment_t = p.T2t(half_way_point)

# split that middle segment (which happens to be the 0th segment here) at the halfway point 
middle_segment_first_half, middle_segment_second_half = p[segment_index].split(segment_t)

# reconstruct the two paths
first_half = Path(*(p[:segment_index - 1] + [middle_segment_first_half]))
second_half = Path(*([middle_segment_second_half] + p[segment_index + 1:]))

# this line will draw the example and open in the default app
disvg(paths=[p.translated(-100j), first_half, second_half], colors='bgr')
thednp commented 4 years ago

@mathandy thanks for the input.

I have for instance these 2 paths (cubic-bezier)

// path1.length = 10
let path1 = [["M",38.01,5.653],
["C",38.01,5.653,564.541,5.653,564.541,5.653],
["C",582.4459999999999,5.653,596.963,20.169,596.963,38.075],
["C",596.963,38.074999999999996,596.963,564.606,596.963,564.606],
["C",596.963,582.511,582.4459999999999,597.028,564.541,597.028],
["C",564.5409999999999,597.028,38.01,597.028,38.01,597.028],
["C",20.104,597.028,5.588000000000001,582.511,5.588000000000001,564.606],
["C",5.588000000000001,564.606,5.588000000000001,38.075,5.588,38.075],
["C",5.588,20.169,20.104,5.653,38.01,5.653],
["C",38.01,5.653,38.01,5.653,38.01,5.653]];

// path2.length = 11
let path2 = [["M",301.113,12.011],
["C",301.113,12.011,400.363,192.007,400.363,192.007],
["C",400.363,192.007,602.227,230.785,602.227,230.785],
["C",602.227,230.785,461.706,380.808,461.706,380.808],
["C",461.706,380.808,487.214,584.766,487.214,584.766],
["C",487.214,584.766,301.113,497.4789999999999,301.113,497.479],
["C",301.113,497.4789999999999,115.01,584.766,115.01,584.766],
["C",115.01,584.766,140.517,380.808,140.517,380.808],
["C",140.517,380.808,0,230.785,0,230.785],
["C",0,230.785,201.86,192.007,201.86,192.007],
["C",201.86,192.007,301.113,12.011,301.113,12.011]];

For each point in path1 split the curve in 2 and for each point in path2 split the curve in 2, is it possible? Would this make my 2 paths have the same amount of curves?

What do you think about it?

thednp commented 4 years ago

Forgot to mention, I made a quick utility to getTotaltLength() on each point for both paths, should I split path1[point1] at that length of path2[point1] and path2[point1] at that length of path1[point1] or at half the length from previous point?