从圆弧计算三次贝塞尔曲线的控制点
Calculate the control points for cubic Bézier curve from an arc
我有一个由两个端点 (P0 = x1,y1 和 P4 = x2,y2) 和半径 R 或圆心 (C = xc, yc) 定义的几何圆弧。我需要为 javascript 中的三次贝塞尔曲线计算两个控制点 P2、P3。在我的特殊情况下,弧角将小于 90 度。
我在互联网和 Whosebug 上搜索过,任何解决方案都不完整,没有针对不确定角度的弧进行概括,或者太复杂我无法理解。
有没有人有任何 javascript 代码或伪代码可以提供帮助?我之前问过一个类似的问题,但当我需要三次贝塞尔曲线时,我不正确地将贝塞尔曲线称为二次曲线。
圆弧的三次贝塞尔近似,由圆的起点和终点坐标、圆心和半径定义 – (x1,y1) = P0, (x2,y2) = P3, C = (cx,cy), R
.
(可以找到由角度定义的 arс 的近似值 here)
贝塞尔曲线的控制点应该在圆上给定点的切线上。一种可能的近似方法——(对称)曲线的中点应位于圆上。
(注意为了好的近似弧度角不能大)
给定点的半径向量:
V1 = (x1-cx, y1 - cy)
V2 = (x2-cx, y2 - cy)
切向量:
T1 = (cy – y1, x1 – cx)
T2 = (y2 - cy, cx – x2)
控制点坐标(k – 未知因子):
P1 = P0 + k * T1
P2 = P3 + k * T2
贝塞尔曲线的中点:
MB = B(1/2) = P0 * 1/8 + P1 * 3/8 + P2 * 3/8 + P3 * 1/8 =
P0 * 1/8 + P0 * 3/8 + k * T1 * 3/8 + P3 * 3/8 + k * T2 * 3/8 + P3 * 1/8 =
(P0 + P3)/2 + k * 3/8 * (T1 +T2)
现在根据 k 因子求解方程
(MB.X – cx)^2 + (MB.Y – cy)^2 = R^2
有两种可能的解决方案——如果输入点的顺序正确(通常情况下弧 < Pi - 具有最小幅度),我们需要正解
Delphi 代码(不检查输入数据,不处理额外情况)及其结果:
procedure BezierArcByPoints(x1, y1, x2, y2, cx, cy, R: Integer;
var Pts: array of TPoint);
var
t1x, t1y, t2x, t2y, dx, dy, k, tx, ty, D, a, b, c: Double;
begin
t1x := cy - y1;
t1y := x1 - cx;
t2x := y2 - cy;
t2y := cx - x2;
dx := (x1 + x2) / 2 - cx;
dy := (y1 + y2) / 2 - cy;
tx := 3 / 8 * (t1x + t2x);
ty := 3 / 8 * (t1y + t2y);
a := tx * tx + ty * ty;
b := dx * tx + dy * ty;
c := dx * dx + dy * dy - R * R;
D := b * b - a * c;
if D > 0 then begin
k := (Sqrt(D) - b) / a;
Pts[0] := Point(x1, y1);
Pts[3] := Point(x2, y2);
Pts[1] := Point(x1 + Round(k * t1x), y1 + Round(k * t1y));
Pts[2] := Point(x2 + Round(k * t2x), y2 + Round(k * t2y));
end;
end;
var
Pts: array [0 .. 3] of TPoint;
an1, an2: Double;
begin
an1 := 0;
an2 := Pi / 2;
Canvas.Pen.Color := clBlue;
Canvas.Pen.Width := 1;
Canvas.Ellipse(100, 100, 301, 301);
BezierArcByPoints(200 + Round(100 * Cos(an1)),
200 + Round(100 * Sin(an1)),
200 + Round(100 * Cos(an2)),
200 + Round(100 * Sin(an2)),
200, 200, 100, Pts);
Canvas.Pen.Color := clRed;
Canvas.Pen.Width := 3;
Canvas.PolyBezier(Pts);
end;
我有一个由两个端点 (P0 = x1,y1 和 P4 = x2,y2) 和半径 R 或圆心 (C = xc, yc) 定义的几何圆弧。我需要为 javascript 中的三次贝塞尔曲线计算两个控制点 P2、P3。在我的特殊情况下,弧角将小于 90 度。
我在互联网和 Whosebug 上搜索过,任何解决方案都不完整,没有针对不确定角度的弧进行概括,或者太复杂我无法理解。
有没有人有任何 javascript 代码或伪代码可以提供帮助?我之前问过一个类似的问题,但当我需要三次贝塞尔曲线时,我不正确地将贝塞尔曲线称为二次曲线。
圆弧的三次贝塞尔近似,由圆的起点和终点坐标、圆心和半径定义 – (x1,y1) = P0, (x2,y2) = P3, C = (cx,cy), R
.
(可以找到由角度定义的 arс 的近似值 here)
贝塞尔曲线的控制点应该在圆上给定点的切线上。一种可能的近似方法——(对称)曲线的中点应位于圆上。
(注意为了好的近似弧度角不能大)
给定点的半径向量:
V1 = (x1-cx, y1 - cy)
V2 = (x2-cx, y2 - cy)
切向量:
T1 = (cy – y1, x1 – cx)
T2 = (y2 - cy, cx – x2)
控制点坐标(k – 未知因子):
P1 = P0 + k * T1
P2 = P3 + k * T2
贝塞尔曲线的中点:
MB = B(1/2) = P0 * 1/8 + P1 * 3/8 + P2 * 3/8 + P3 * 1/8 =
P0 * 1/8 + P0 * 3/8 + k * T1 * 3/8 + P3 * 3/8 + k * T2 * 3/8 + P3 * 1/8 =
(P0 + P3)/2 + k * 3/8 * (T1 +T2)
现在根据 k 因子求解方程
(MB.X – cx)^2 + (MB.Y – cy)^2 = R^2
有两种可能的解决方案——如果输入点的顺序正确(通常情况下弧 < Pi - 具有最小幅度),我们需要正解
Delphi 代码(不检查输入数据,不处理额外情况)及其结果:
procedure BezierArcByPoints(x1, y1, x2, y2, cx, cy, R: Integer;
var Pts: array of TPoint);
var
t1x, t1y, t2x, t2y, dx, dy, k, tx, ty, D, a, b, c: Double;
begin
t1x := cy - y1;
t1y := x1 - cx;
t2x := y2 - cy;
t2y := cx - x2;
dx := (x1 + x2) / 2 - cx;
dy := (y1 + y2) / 2 - cy;
tx := 3 / 8 * (t1x + t2x);
ty := 3 / 8 * (t1y + t2y);
a := tx * tx + ty * ty;
b := dx * tx + dy * ty;
c := dx * dx + dy * dy - R * R;
D := b * b - a * c;
if D > 0 then begin
k := (Sqrt(D) - b) / a;
Pts[0] := Point(x1, y1);
Pts[3] := Point(x2, y2);
Pts[1] := Point(x1 + Round(k * t1x), y1 + Round(k * t1y));
Pts[2] := Point(x2 + Round(k * t2x), y2 + Round(k * t2y));
end;
end;
var
Pts: array [0 .. 3] of TPoint;
an1, an2: Double;
begin
an1 := 0;
an2 := Pi / 2;
Canvas.Pen.Color := clBlue;
Canvas.Pen.Width := 1;
Canvas.Ellipse(100, 100, 301, 301);
BezierArcByPoints(200 + Round(100 * Cos(an1)),
200 + Round(100 * Sin(an1)),
200 + Round(100 * Cos(an2)),
200 + Round(100 * Sin(an2)),
200, 200, 100, Pts);
Canvas.Pen.Color := clRed;
Canvas.Pen.Width := 3;
Canvas.PolyBezier(Pts);
end;