开源改变世界!!

SVG导入 #902

推推 grbl 2年前 (2023-02-01) 148次浏览
关闭
Harvie 打开了这个问题 2018 年 7 月 3 日 · 9条评论
关闭

SVG导入#902

Harvie 打开了这个问题 2018 年 7 月 3 日 · 9条评论

注释

SVG导入 #902
合作者

这看起来很容易集成到 bCNC:

https://github.com/vishpat/svg2gcode

SVG导入 #902
贡献者

注意:
https: //www.gnu.org/licenses/gpl-faq.html Greetz Steve
SVG导入 #902

SVG导入 #902
合作者作者

我想我们可以请原作者为我们重新授权。很有可能他只是在没有任何特定原因的情况下获得了 GPLv3…:-)

SVG导入 #902
合作者作者
哈维 评论了 2018 年 7 月 12 日  

这个可能两者都可以。进出口。我会试试看:
https ://github.com/mathandy/svgpathtools https://pypi.org/project/svgpathtools/

更新:它在路径中输出贝塞尔曲线,所以它不太适合生成 g 代码…
更新 2:mathandy/svgpathtools#61

SVG导入 #902
合作者作者
哈维 评论了 2018 年 8 月 17 日  

SVG导入 #902

SVG 导出:

SVG导入 #902

SVG导入 #902
合作者作者
哈维 评论了 2018 年 8 月 18 日  

这些人还有一些用于 SVG 路径线性化的 python 代码:
https ://pypi.org/project/SVGCompress/#files

像这样工作:

from svg_compression import *
comp_instance = Compress("test/test_vector.svg")
comp_instance.find_paths()                        # Extract path coordinates
comp_instance.linearize_paths(curve_fidelity = 10)     # Convert paths into polygons
#comp_instance.write(outputfile = "hrv.svg")
#print(comp_instance.linear_coords[0])
for path in comp_instance.linear_coords:
        p = path[0]
        print("g0 x%s y%s"%(str(p[0]),str(p[1])))
        for p in path:
                print("g1 x%s y%s"%(str(p[0]),str(p[1])))

我们也可以扔掉大部分库及其依赖项

但是我们应该禁用圆弧线性化,因为我们可以在本地进行圆弧。

SVG导入 #902
合作者作者
哈维 评论了 2018 年 8 月 18 日  

我已经从库中删除了所有不需要的东西(GPLv3+):
svg_gcode.py:

import numpy
import svg.path
import lxml.etree as ET

'''
Compress svg figure through a variety of methods
Written July 22, 2014
Author: Gen Del Raye
'''

class SVGcode:

	def __init__(self, svg_file):
		'''
		Read svg from path 'svg_file' (e.g. 'test/test_vector.svg')
		'''
		#self.filename, self.extension = svg_file.split('.') # Get filename and extension
		#assert self.extension == 'svg', 'File must be an svg'
		try:
			self.figure_data = ET.parse(svg_file) # Parse svg data as xml
		except ET.XMLSyntaxError, e:
			'''
			Large svgs may trigger lxml's 'excessive depth in document' exception
			'''
			warnings.warn('lxml error: %s - Trying huge xml parser' %(e.message))
			huge_parser = ET.XMLParser(huge_tree = True)
			self.figure_data = ET.parse(svg_file, parser = huge_parser)
		self.root = self.figure_data.getroot() # Root object in svg

	def find_paths(self):
		'''
		Find and parse nodes in the xml that correspond to paths in the svg
		'''
		tag_prefix = '{*}'
		self.path_nodes = self.root.findall('.//%spath' %(tag_prefix))
		self.paths = list()
		self.paths = [svg.path.parse_path(p.attrib.get('d', 'M 0,0 z')) for p in self.path_nodes]

	def linearize_paths(self, curve_fidelity = 10):
		'''
		Turn svg paths into discrete lines
		Inputs:
			curve_fidelity(int) - number of lines with which to approximate curves
				in svg. Higher values necessitates longer computation time.
		'''
		self.linear_coords = [self.linearize(p, curve_fidelity) for p in self.paths]


	def linearize_line(self, segment, n_interpolate = None):
		'''
		Turn svg line into set of coordinates by returning
		start and end coordinates of the line segment.
		n_interpolate is only used for consistency of use
		with linearize_curve()
		'''
		return numpy.array([segment.start, segment.end])

	def linearize_curve(self, segment, n_interpolate = 10):
		'''
		Estimate svg curve (e.g. Bezier, Arc, etc.) using
		a set of n discrete lines. n_interpolate sets the
		number of discrete lines per curve.
		'''
		interpolation_pts = numpy.linspace(0, 1, n_interpolate, endpoint = False)[1:]
		interpolated = numpy.zeros(n_interpolate + 1, dtype = complex)
		interpolated[0] = segment.start
		interpolated[-1] = segment.end
		for i, pt in enumerate(interpolation_pts):
				interpolated[i + 1] = segment.point(pt)
		return interpolated

	def complex2coord(self, complexnum):
		return (complexnum.real, complexnum.imag)

	def linearize(self, path, n_interpolate = 10):
		segmenttype2func = {'CubicBezier': self.linearize_curve,
				    'Line': self.linearize_line,
				    'QuadraticBezier': self.linearize_curve,
				    'Arc': self.linearize_curve}
		'''
		More sophisticated linearization option
		compared to endpts2line().
		Turn svg path into discrete coordinates
		with number of coordinates per curve set
		by n_interpolate. i.e. if n_interpolate
		is 100, each curve is approximated by
		100 discrete lines.
		'''
		segments = path._segments
		complex_coords = list()
		for segment in segments:
			# Output coordinates for each segment, minus last point (because
			# point is same as first point of next segment)
			segment_type = type(segment).__name__
			segment_linearize = segmenttype2func[segment_type]
			linearized = segment_linearize(segment, n_interpolate)
			complex_coords.extend(linearized[:-1])
		# Append last point of final segment to close the polygon
		complex_coords.append(linearized[-1])
		return [self.complex2coord(complexnum) for complexnum in complex_coords] # Output list of (x, y) tuples

测试.py

from svg_gcode import *
comp_instance = SVGcode("test/test_vector.svg")
comp_instance.find_paths()                        # Extract path coordinates
comp_instance.linearize_paths(curve_fidelity = 10)     # Convert paths into polygons
#comp_instance.write(outputfile = "hrv.svg")
#print(comp_instance.linear_coords[0])
for path in comp_instance.linear_coords:
	p = path[0]
	print("g0 x%s y%s"%(str(p[0]),str(p[1])))
	for p in path:
		print("g1 x%s y%s"%(str(p[0]),str(p[1])))
	print "( ---------- cut-here ---------- )"

仍然需要一些清理,但 100 LoC 已经不错了。事实上,大部分魔法都是在 svg.path 和 numpy 中完成的。

我们还应该根据段长度设置子段数,比如QuadraticBezier.length()

Harvie 向 Harvie/bCNC 添加了引用此问题的提交 2018 年 8 月 21 日

SVG导入 #902
合作者作者
哈维 评论了 2018 年 8 月 21 日  

我无法联系到 SVGCompress 的作者对其进行双重许可,所以我最终从头开始编写自己的 SVG2Gcode 转换器,而且它更简单!

Harvie 向 Harvie/bCNC 添加了引用此问题的提交 2018 年 9 月 5 日

SVG导入 #902
合作者作者

实施的