我正在开发HTML5画布游戏。
我想在两点之间绘制一个S形的三次贝塞尔曲线,但我正在寻找一种计算控制点坐标的方法,这样曲线本身总是相同的长度,无论这些点有多接近是,直到它到达曲线变成直线的点。
答案 0 :(得分:2)
这可以用数字方法解决。我假设你有一个带有4个控制点的立方贝塞尔曲线。 在每个步骤中,您有第一个(P0)和最后一个(P3)点,并且您想要计算P1和P2,使得总长度不变。
添加此约束会移除一个自由度,因此我们有1个左边(从4开始,确定终点(-2),常量长度是另一个-1)。所以你需要做出决定。
贝塞尔曲线是一个定义在0和1之间的多项式,你需要积分在元素之和(2d?)的平方根上。对于一个三次贝塞尔曲线,这意味着一个6度多项式的sqrt,其中wolfram不知道如何解决。但是,如果已知所有其他控制点(或者已知某些其他约束的依赖关系),则可以为该约束设置一个预先计算值的保存表。
答案 1 :(得分:2)
曲线是否真的有必要是贝塞尔曲线? 安装两个总长度恒定的圆弧更容易。你将永远得到一个S形。
安装两个圆弧:
让 D 成为端点之间的欧氏距离。让 C 成为我们想要的恒定长度。我得到了 b 的以下表达式(在图像中绘制):
b = sqrt(D*sin(C/4)/4 - (D^2)/16)
我没有检查它是否正确,所以如果有人得到不同的东西,请发表评论。
编辑:你应该考虑我在解决方程时得到的负解,并检查哪一个是正确的。
b = -sqrt(D*sin(C/4)/4 - (D^2)/16)
答案 2 :(得分:0)
以下是SVG的一个工作示例:关闭来纠正:
http://phrogz.net/svg/constant-length-bezier.xhtml
我通过实验确定,当端点位于彼此之上时,手柄应为
desiredLength × cos(30°)
远离手柄; (当然)当终点处于最大距离时,把手应该在彼此的顶部。绘制所有理想点看起来像一样像椭圆一样:
蓝线是实际的理想方程,而上面的红线是近似理想的椭圆。使用椭圆的等式(如上面的例子所示)允许线在中间得到大约9%的长度。
以下是相关的JavaScript代码:
// M is the MoveTo command in SVG (the first point on the path)
// C is the CurveTo command in SVG:
// C.x is the end point of the path
// C.x1 is the first control point
// C.x2 is the second control point
function makeFixedLengthSCurve(path,length){
var dx = C.x - M.x, dy = C.y - M.y;
var len = Math.sqrt(dx*dx+dy*dy);
var angle = Math.atan2(dy,dx);
if (len >= length){
C.x = M.x + 100 * Math.cos(angle);
C.y = M.y + 100 * Math.sin(angle);
C.x1 = M.x; C.y1 = M.y;
C.x2 = C.x; C.y2 = C.y;
}else{
// Ellipse of major axis length and minor axis length*cos(30°)
var a = length, b = length*Math.cos(30*Math.PI/180);
var handleDistance = Math.sqrt( b*b * ( 1 - len*len / (a*a) ) );
C.x1 = M.x + handleDistance * Math.sin(angle);
C.y1 = M.y - handleDistance * Math.cos(angle);
C.x2 = C.x - handleDistance * Math.sin(angle);
C.y2 = C.y + handleDistance * Math.cos(angle);
}
}