【问题标题】:Sample points on an svg pathsvg 路径上的样本点
【发布时间】:2021-06-18 08:47:39
【问题描述】:

给定一个 SVG(包含单个路径对象),我想将路径分成 n 个等长的段。返回值应该是光栅化 svg 中 (n+1) 点 (x, y) 坐标的列表,指示每个段的结束

例子:

给定 SVG:(此示例只有直线,但该解决方案必须适用于所有类型的路径,包括三次和二次贝塞尔曲线)

<svg height="210" width="400">
  <path d="M150 0 L75 200 L225 200 Z" fill="none" stroke="black" stroke-width="4" />
</svg>

呈现为

预期输出:以左下角为原点的每个红点的坐标。 SVG 总是以 width=100px 呈现

我正在使用python和svgpathtools,我该如何实现?

我的方法:

  1. 看看 SVG 光栅化器。看看他们如何处理路径。我查看了this,但遗憾的是无法很好地理解代码以自己实现它
  2. stroke-dasharray 添加到我的路径。 stroke-dasharray 将自动将连续笔划“分解”成相等大小的段。然后光栅化这个修改后的 SVG,然后使用 OpenCV 之类的东西来聚类渲染的笔画。然后找到这些簇的中点来得到答案。由于涉及多个缓慢的过程(光栅化+集群),这种方法非常慢。如果路径与自身交叉(无穷大符号),它也不是很灵活,因为stroke-dasharray 也会相交,给出一个奇怪的交叉点
  3. 我查看了this question,但我不确定在 SVG 始终以宽度 = 100px 呈现(高度根据 SVG 的纵横比自动计算)的情况下这将如何工作,此外,这里提到的方法是据说“慢”。此外,我不确定这个链接的问题是否让我“在”路径上点或 svg 路径的控制点

虽然方法 2 适用于许多图像,但我当然不想这样做,因为它非常慢。有更好的方法吗?

【问题讨论】:

    标签: python svg vector-graphics


    【解决方案1】:

    给定一个 SVG(包含单个路径对象),我想划分 将路径分成 n 段等长。

    我使用了满足两个条件时出现点的效果:

    1. 属性stroke-dasharray = "(0, N)" 中的笔划(破折号)长度必须为零
    2. stroke-lineCap="round"

    我使用getTotalLength() JS 方法来获取一个 SVG 元素的全行长度

    正如您在控制台中看到的,结果是 ~= 577.2px

    假设我们需要将线的长度分成11等分:

    577,2 / 11 = 52.47 在这种情况下,stroke-dasharray =" 0, 52.47 "

    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="210" width="400">
      <path stroke-dasharray="0,52.47"  stroke-lineCap="round" id="p1" d="M150 0 L75 200 L225 200 Z" fill="none" stroke="black" stroke-width="4" />
    </svg>
    <script>
    console.log(p1.getTotalLength() / 11); 
    </script>

    对于 22 个相等的线段:

    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="210" width="400">
      <path stroke-dasharray="0,26.23"  stroke-lineCap="round" id="p1" d="M150 0 L75 200 L225 200 Z" fill="none" stroke="black" stroke-width="4" />
    </svg>
    <script>
    console.log(p1.getTotalLength() /22); 
    </script>

    你可以增加stroke-width,点的直径会按比例增加,但点的中心之间的距离保持不变。

    stroke-width="8"

    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="210" width="400">
      <path stroke-dasharray="0,26.23"  stroke-lineCap="round" id="p1" d="M150 0 L75 200 L225 200 Z" fill="none" stroke="black" stroke-width="8" />
    </svg>
    <script>
    console.log(p1.getTotalLength() / 22); 
    </script>

    更新

    评论了@ashutoshbsathe

    在接受它之前,我会尝试使用更多的 SVG 最终答案

    测试这种将周长分成N等份的技术对SVG的不同图形的普遍性

    #1。将正方形分成4部分

    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="300">
            <!-- Background rectangle -->
     <path  id="back" d="M50 10 L250 10 L250 210 50 210Z" fill="none" stroke="grey" stroke-width="2" /> 
                 <!-- Divide into 4 equal parts using the stroke-dasharray  -->
     <path id="p1" stroke-dasharray="0,200"  stroke-lineCap="round"  d="M50 10 L250 10 L250 210 50 210Z" fill="none" stroke="red" stroke-width="8" />
    </svg>
    <script>
    console.log(p1.getTotalLength() / 4); 
    </script>

    #2。将正方形分成16份

    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="300">
            <!-- Background rectangle -->
     <path  id="back" d="M50 10 L250 10 L250 210 50 210Z" fill="none" stroke="grey" stroke-width="2" /> 
                 <!-- Divide into 8 equal parts using the stroke-dasharray  -->
     <path id="p1" stroke-dasharray="0,50"  stroke-lineCap="round"  d="M50 10 L250 10 L250 210 50 210Z" fill="none" stroke="red" stroke-width="8" />
    </svg>
    <script>
    console.log(p1.getTotalLength() / 16); 
    </script>

    #3。把星星分成5个部分

    <style>
    #back {
    fill:none;
    stroke:black;
    stroke-width:2;
    }
    #p1 {
    fill:none;
    stroke:red;
    stroke-width:8;
    stroke-dasharray:0,179.95;
    stroke-lineCap:round;
    }
    
    </style>
    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="300" viewBox="0 0 300 300">
       <!-- Background star -->
       <polygon id="back" points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>
          <!--  red dots 5 -->
      <polygon id="p1" points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>
    </svg>
    <script>
    console.log(p1.getTotalLength() / 5); 
    </script>

    #4。把星星分成10份

    <style>
    #back {
    fill:none;
    stroke:black;
    stroke-width:2;
    }
    #p1 {
    fill:none;
    stroke:red;
    stroke-width:8;
    stroke-dasharray:0,89.978;
    stroke-lineCap:round;
    }
    
    </style>
    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="300" viewBox="0 0 300 300">
       <!-- Background star -->
       <polygon id="back" points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>
          <!--  red dots 10 -->
      <polygon id="p1" points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>
    </svg>
    <script>
    console.log(p1.getTotalLength() / 10); 
    </script>

    #5。将六边形分成6份

    <style>
    #back {
    fill:none;
    stroke:black;
    stroke-width:1;
    }
    #p1 {
    fill:none;
    stroke:red;
    stroke-width:4;
    stroke-dasharray:0,31.64;
    stroke-lineCap:round;
    }
    
    </style>
    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="300" viewBox="-5 0 100 100">
       <!-- Background hexagon -->
       <path id="back"  d="M48.9 60.9 16.9 60.9 1.2 33.4 17.1 6.1 48.7 6.2 64.4 33.6z"/>
          <!-- Six red dots -->
      <path id="p1"  d="M48.9 60.9 16.9 60.9 1.2 33.4 17.1 6.1 48.7 6.2 64.4 33.6z"/>
    </svg>
    <script>
    console.log(p1.getTotalLength() / 6); 
    </script>

    #6。将六边形分成12份

    #back {
    fill:none;
    stroke:black;
    stroke-width:1;
    }
    #p1 {
    fill:none;
    stroke:red;
    stroke-width:4;
    stroke-dasharray:0,15.82;
    stroke-lineCap:round;
    }
    <svg xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink" height="300" width="300" viewBox="-5 0 100 100">
       <!-- Background hexagon -->
       <path id="back"  d="M48.9 60.9 16.9 60.9 1.2 33.4 17.1 6.1 48.7 6.2 64.4 33.6z"/>
          <!--  red dots 12 -->
      <path id="p1"  d="M48.9 60.9 16.9 60.9 1.2 33.4 17.1 6.1 48.7 6.2 64.4 33.6z"/>
    </svg>
    <script>
    console.log(p1.getTotalLength() /12); 
    </script>

    【讨论】:

    • 这看起来很有希望,在接受这个作为最终答案之前,我会用更多的 SVG 尝试一下
    • @ashutoshbsathe 感谢您的积极反馈。为这个想法投赞成票会很好
    • 嗨@Alexandr_TT 在忙碌的一周里一直在运行,所以还不能彻底测试这个。它似乎适用于我在此处发布的示例。我测试的其他示例(并且根本不起作用)是我公司的机密财产,我将尝试在没有版权的其他地方找到类似的图像并将其发布在这里
    • @ashutoshbsathe 我理解你。我会等待你的例子。我现在添加了新的例子。请看这里
    • @ashutoshbsathe I will try to find a similar image elsewhere without copyrights and post it here - 你在寻找合适的路径方面做得如何?
    猜你喜欢
    • 1970-01-01
    • 2020-04-08
    • 2017-03-19
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 2018-01-30
    相关资源
    最近更新 更多