【问题标题】:Converting a list of points to an SVG cubic piecewise Bezier curve将点列表转换为 SVG 三次分段贝塞尔曲线
【发布时间】:2020-07-11 22:38:20
【问题描述】:

我有一个点列表,并希望尽可能顺利地连接它们。我有一个函数可以评估以获得这些分数。我可以简单地使用更多的采样点,但这只会增加 SVG 文件的大小。我认为使用分段三次贝塞尔曲线会更适合。我该怎么做呢?

我做了一些研究,发现了 svgpathtools 包,它看起来很有希望。但是,我没有找到任何类似的功能。

【问题讨论】:

  • 我可以告诉你在 javascript 中遵循的逻辑。你能把它翻译成python吗?
  • 使用向心 Catmull-Rom 样条曲线来创建对点进行插值的曲线。该曲线由多条三次贝塞尔曲线组成。然后,您可以使用 SVG 的路径绘制曲线。
  • @enxaneta 是的,我认为这可行。

标签: python svg bezier


【解决方案1】:

如果您曾经使用过 Illustrator,您肯定记得贝塞尔曲线的第一个控制点与前一个控制点的最后一个控制点相连。这条线与曲线相切。在我的代码中,我使用这条线的大小来绘制曲线。

另外:第一条和最后一条曲线是二次贝塞尔曲线(只有一个控制点)。所有其他曲线都是三次贝塞尔曲线(2 个控制点)。

// size of the tangent
var t = 1 / 5;

// points array
var p = [{
  x: 100,
  y: 100
}, {
  x: 250,
  y: 150
}, {
  x: 300,
  y: 300
}, {
  x: 450,
  y: 250
}, {
  x: 510,
  y: 140
}, {
  x: 590,
  y: 250
}, {
  x: 670,
  y: 140
}];

function controlPoints(p) {
  // given the points array p calculate the control points for the cubic Bezier curves

  var pc = [];
  for (var i = 1; i < p.length - 1; i++) {
    var dx = p[i - 1].x - p[i + 1].x; // difference x
    var dy = p[i - 1].y - p[i + 1].y; // difference y
    // the first control point
    var x1 = p[i].x - dx * t;
    var y1 = p[i].y - dy * t;
    var o1 = {
      x: x1,
      y: y1
    };

    // the second control point
    var x2 = p[i].x + dx * t;
    var y2 = p[i].y + dy * t;
    var o2 = {
      x: x2,
      y: y2
    };

    // building the control points array
    pc[i] = [];
    pc[i].push(o1);
    pc[i].push(o2);
  }
  return pc;
}

function drawCurve(p) {

  var pc = controlPoints(p); // the control points array
  
  let d =`M${p[0].x},${p[0].y}
Q${pc[1][1].x},${pc[1][1].y}, ${p[1].x},${p[1].y}
`
  if (p.length > 2) {
    // central curves are cubic Bezier
    for (var i = 1; i < p.length - 2; i++) {
    d += `C${pc[i][0].x}, ${pc[i][0].y}, ${pc[i + 1][1].x}, ${pc[i + 1][1].y}, ${p[i + 1].x},${p[i + 1].y}`;
    }
  
    // the first & the last curve are quadratic Bezier
    var n = p.length - 1;
    d+= `Q${pc[n - 1][0].x}, ${pc[n - 1][0].y}, ${p[n].x}, ${p[n].y}`;

}
  return d
}


thePath.setAttribute("d", drawCurve(p))
svg{border:solid; fill:none;stroke:black;}
<svg id = 'svg' viewBox="0 0 800 400">
  <path id="thePath" />
</svg>

这是一支钢笔,我在画布 https://codepen.io/enxaneta/pen/PqLNLv 中做同样的事情。在这里你可以看到切线。

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 2016-10-05
    • 2012-07-27
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 2017-12-12
    相关资源
    最近更新 更多