将点列表转换为SVG三次分段Bezier曲线 [英] Converting a list of points to an SVG cubic piecewise Bezier curve
问题描述
我有一个要点列表,想要尽可能平滑地连接它们.我有一个评估得出这些要点的函数.我可以简单地使用更多采样点,但这只会增加SVG文件的大小.我认为使用分段三次贝塞尔曲线会更合适.我该怎么做呢?
I have a list of points and want to connect them as smoothly as possible. I have a function that I evaluate to get these points. I could simply use more sampling points but that would only increase the SVG file size. I think using a piecewise cubic Bezier curve would be better suited. How do I do this?
我做了一些研究,发现了 svgpathtools 软件包,该软件包看起来很有希望.但是,我没有找到任何类似的功能.
I did some research and came across the svgpathtools package, which looked promising. However, I did not find any functionality like this.
推荐答案
如果您曾经使用过Illustrator,您肯定会记得贝塞尔曲线的第一个控制点与前一个控制点的最后一个控制点相连.这条线与曲线相切.在我的代码中,我使用这条线的大小绘制曲线.
If you ever used Illustrator you certainly remember that the first control points of a bezier is connected with the last control point of the previous one. This line is tangent to the curve. In my code I am using the size of this line to draw the curve.
也:第一个&最后一条曲线是二次贝塞尔曲线(只有一个控制点).所有其他曲线均为三次贝塞尔曲线(2个控制点).
Also: the first & the last curve are quadratic Bezier (only one control point). All the other curves are cubic Bezier (2 control points).
// 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 .在这里您可以看到切线.
This is a pen where I'm doing the same in canvas https://codepen.io/enxaneta/pen/PqLNLv . Here you can see the tangents.
这篇关于将点列表转换为SVG三次分段Bezier曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!