如何获取 svg 路径的点
How to get points of the svg paths
我有一个 SVG 文件,例如这个
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="red"
d="M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z" />
</svg>
如何获取这些路径的点 (x, y) 列表?
我已经看到 that 答案,但它还不够完整,所以我要求完整的解决方案。
我想要一个选项来选择有多少个点或控制点的密度。
假设您想要总共获得 n 分。你只需要这样做:
import numpy as np
import svg.path
n = 10
path = '''M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z'''
pp = svg.path.parse_path(path)
points = [pp.point(pos) for pos in np.linspace(0, 1, n)]
上面例子的输出:
>>> points
[(10+30j),
(29.151135102977165+10.01802241051696j),
(49.92794283866024+28.30380006511909j),
(67.45952198841553+10.162006868822246j),
(89.712290578091+26.619822465475373j),
(84.71079732451658+51.81807142699621j),
(66.11578778154251+76.36355357024713j),
(36.776919717540096+79.09096428650194j),
(16.694229929385042+54.545482143251j),
(10+30j)]
显然,点是复数。
在这里您可以更改点的比例、偏移和密度:
from svg.path import parse_path
from xml.dom import minidom
def get_point_at(path, distance, scale, offset):
pos = path.point(distance)
pos += offset
pos *= scale
return pos.real, pos.imag
def points_from_path(path, density, scale, offset):
step = int(path.length() * density)
last_step = step - 1
if last_step == 0:
yield get_point_at(path, 0, scale, offset)
return
for distance in range(step):
yield get_point_at(
path, distance / last_step, scale, offset)
def points_from_doc(doc, density=5, scale=1, offset=0):
offset = offset[0] + offset[1] * 1j
points = []
for element in doc.getElementsByTagName("path"):
for path in parse_path(element.getAttribute("d")):
points.extend(points_from_path(
path, density, scale, offset))
return points
string = """<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="red"
d="M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z" />
</svg>"""
doc = minidom.parseString(string)
points = points_from_doc(doc, density=1, scale=5, offset=(0, 5))
doc.unlink()
你还可以想象那些点:
import pygame
from svg.path import parse_path
from xml.dom import minidom
... # other functions and string
def main():
screen = pygame.display.set_mode([500, 500])
screen.fill((255, 255, 255))
doc = minidom.parseString(string)
points = points_from_doc(doc, 0.05, 5, (0, 5))
doc.unlink()
for point in points:
pygame.draw.circle(screen, (0, 0, 255), point, 1)
pygame.display.flip()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
pygame.init()
main()
pygame.quit()
density == 0.05
:
density == 0.1
:
density == 0.5
:
density == 1
:
density == 5
:
python 包是不言自明的,其他答案并没有按照他们应该的方式解决问题,基本上他要求得到分数
from xml.dom import minidom
from svg.path import parse_path
with open('test.txt') as f:
content = '\n'.join([line.strip() for line in f.readlines()])
svg_dom = minidom.parseString(content)
path_strings = [path.getAttribute('d') for path in svg_dom.getElementsByTagName('path')]
for path_string in path_strings:
path_data = parse_path(path_string)
print(path_data.d())
#it prints all data in single string
#prints M 10,30 A 20,20 0 0,1 50,30 A 20,20 0 0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 Z
for p in path_data:
#but you can always iterate to get even deep control
print(p.start, p.end) #prints only the star and end points of each path
#e.g. (10+30j) (10+30j)
我有一个 SVG 文件,例如这个
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="red"
d="M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z" />
</svg>
如何获取这些路径的点 (x, y) 列表?
我已经看到 that 答案,但它还不够完整,所以我要求完整的解决方案。
我想要一个选项来选择有多少个点或控制点的密度。
假设您想要总共获得 n 分。你只需要这样做:
import numpy as np
import svg.path
n = 10
path = '''M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z'''
pp = svg.path.parse_path(path)
points = [pp.point(pos) for pos in np.linspace(0, 1, n)]
上面例子的输出:
>>> points
[(10+30j),
(29.151135102977165+10.01802241051696j),
(49.92794283866024+28.30380006511909j),
(67.45952198841553+10.162006868822246j),
(89.712290578091+26.619822465475373j),
(84.71079732451658+51.81807142699621j),
(66.11578778154251+76.36355357024713j),
(36.776919717540096+79.09096428650194j),
(16.694229929385042+54.545482143251j),
(10+30j)]
显然,点是复数。
在这里您可以更改点的比例、偏移和密度:
from svg.path import parse_path
from xml.dom import minidom
def get_point_at(path, distance, scale, offset):
pos = path.point(distance)
pos += offset
pos *= scale
return pos.real, pos.imag
def points_from_path(path, density, scale, offset):
step = int(path.length() * density)
last_step = step - 1
if last_step == 0:
yield get_point_at(path, 0, scale, offset)
return
for distance in range(step):
yield get_point_at(
path, distance / last_step, scale, offset)
def points_from_doc(doc, density=5, scale=1, offset=0):
offset = offset[0] + offset[1] * 1j
points = []
for element in doc.getElementsByTagName("path"):
for path in parse_path(element.getAttribute("d")):
points.extend(points_from_path(
path, density, scale, offset))
return points
string = """<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="red"
d="M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z" />
</svg>"""
doc = minidom.parseString(string)
points = points_from_doc(doc, density=1, scale=5, offset=(0, 5))
doc.unlink()
你还可以想象那些点:
import pygame
from svg.path import parse_path
from xml.dom import minidom
... # other functions and string
def main():
screen = pygame.display.set_mode([500, 500])
screen.fill((255, 255, 255))
doc = minidom.parseString(string)
points = points_from_doc(doc, 0.05, 5, (0, 5))
doc.unlink()
for point in points:
pygame.draw.circle(screen, (0, 0, 255), point, 1)
pygame.display.flip()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
pygame.init()
main()
pygame.quit()
density == 0.05
:
density == 0.1
:
density == 0.5
:
density == 1
:
density == 5
:
python 包是不言自明的,其他答案并没有按照他们应该的方式解决问题,基本上他要求得到分数
from xml.dom import minidom
from svg.path import parse_path
with open('test.txt') as f:
content = '\n'.join([line.strip() for line in f.readlines()])
svg_dom = minidom.parseString(content)
path_strings = [path.getAttribute('d') for path in svg_dom.getElementsByTagName('path')]
for path_string in path_strings:
path_data = parse_path(path_string)
print(path_data.d())
#it prints all data in single string
#prints M 10,30 A 20,20 0 0,1 50,30 A 20,20 0 0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 Z
for p in path_data:
#but you can always iterate to get even deep control
print(p.start, p.end) #prints only the star and end points of each path
#e.g. (10+30j) (10+30j)