【问题标题】:How to get points of the svg paths如何获取 svg 路径的点
【发布时间】:2021-11-17 16:06:15
【问题描述】:

我有一个 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 的回答,但它不完整,所以我要求完整的解决方案。

我想有一个选项来选择有多少点或控制点的密度。

【问题讨论】:

  • 分享您的研究对每个人都有帮助。告诉我们您尝试了什么以及为什么它不能满足您的需求。这表明您已经花时间尝试帮助自己,它使我们免于重复明显的答案,最重要的是它可以帮助您获得更具体和相关的答案!另见:How to Ask

标签: python svg


【解决方案1】:

假设您想要总共有 ​​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)]

显然,点是复数。

【讨论】:

    【解决方案2】:

    您可以在此处更改点的比例、偏移和密度:

    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:

    【讨论】:

      【解决方案3】:

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-10
        • 2020-08-12
        • 2022-01-13
        • 1970-01-01
        • 2014-05-03
        • 1970-01-01
        • 1970-01-01
        • 2017-08-19
        相关资源
        最近更新 更多