mathandy / svgpathtools

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

Convert SVG to list of lines and arcs #61

Closed Harvie closed 6 years ago

Harvie commented 6 years ago

Hello, i am working on SVG to g-code convertor for bCNC and i need way to subdivide the SVG to list of paths made just from LINEs and ARCs. Because g-code does not support anything else except lines and arcs. Is there way to do this using your library? That would mean to approximate and replace both Bezier types using lines (or arcs).

SebKuzminsky commented 6 years ago

The LinuxCNC G-code dialect supports cubic and quadratic splines, as well as non-uniform rational b-splines.

That said, if you want to convert SVG splines to lines, code like this will do that.

And, if you want to convert an SVG path to G-code, the https://github.com/SebKuzminsky/svg2gcode/ tool will do that (based on svgpathtools). :-)

Harvie commented 6 years ago

@SebKuzminsky I don't use LinuxCNC and unfortunately both bCNC and GRBL do not understand splines. I'll try to look at svg2gcode of yours to check if that has spline linearization. But it's of no use for me if that's not a case.

SebKuzminsky commented 6 years ago

svg2gcode does linear approximation of splines, and of elliptic arcs, which are also not supported by G-code: https://github.com/SebKuzminsky/svg2gcode/blob/master/gcoder.py#L760

Harvie commented 6 years ago

That would be great, because both bCNC and GRBL only understand G0, G1, G2 and G3... I'll try it. update: i have some troubles to get cairosvg working on python2, also it's GPLv3 and bCNC is GPLv2 only, so bCNC people can't include it.

SebKuzminsky commented 6 years ago

I'll be happy to dual-license the code. Please open a detailed issue in https://github.com/SebKuzminsky/svg2gcode and I'll try to get to it next week.

Harvie commented 6 years ago

svg2gcode license is GPLv2, that's OK. but cairosvg is GPLv3. Are you also maintainer of cairosvg?

SebKuzminsky commented 6 years ago

@Harvie I misunderstood what you were saying, sorry. I am the author/maintainer of svg2gcode, but I'm not a maintainer of cairosvg. svg2gcode is licensed "GPLv2+" and cairosvg is "LGPL3+". According to the GNU compatibility matrix that's ok, and the effective license of the combined work is "GPL3+". If you wanted to copy just the spline-linear-approximation code out of svg2gcode and incorporate it into bCNC, my understanding is that that would be perfectly ethical and legal, since svg2gcode itself is GPLv2+. I certainly wouldn't have any problem with it. @mathandy Sorry for this off-topic discussion in your issue tracker... @Harvie please contact me via email or in the svg2gcode issue tracker if you want to continue this conversation.

mathandy commented 6 years ago

@Harvie you could convert to lines pretty simply

See compute-many-points-quickly-using-numpy-arrays.py

You could also use the inverse arclength method ilength(). To make a more robust or faster method, you'd probably want to go about finding the max curvature -- which might be a useful function to add.

A piecewise linear interpolation feature has been requested before. It'd be a nice addition. If you make a robust solution (e.g. something guaranteed to be within some controllable measure of accuracy), please contribute a pull-request.

mathandy commented 6 years ago

@Harvie E.g. for a (probably overly) simple solution,

from svgpathtools import *
import numpy as np

def approximate_with_lines(curve, how_many_lines_to_use=1000):
    pts = [old_path.point(t) for t in np.linspace(0, 1, how_many_lines_to_use)]
    return Path(*[Line(pts[i-1], pts[i]) for i in range(1, len(pts))])

# test
old_path = Path(CubicBezier(0, 3+3j, 4j, 1+1j))
new_path_3 = approximate_with_lines(old_path, 3)  # using only 3 lines
new_path_5 = approximate_with_lines(old_path, 5)  # using 5 lines
new_path_10 = approximate_with_lines(old_path, 10)  # using 10 lines

disvg([old_path, new_path_3, new_path_5, new_path_10], 'bygr')