2015-12-25 5 views
0

У меня есть геометрическая дуга, определяемая двумя конечными точками (P0 = x1, y1 и P4 = x2, y2) и либо радиус R, либо центр дуги (C = xc, yc). Мне нужно вычислить две контрольные точки P2, P3 для кубической кривой Безье в javascript. В моем конкретном случае угол дуги будет меньше 90 градусов.Вычислите контрольные точки для кубической кривой Безье из дуги

У меня есть поиск в Интернете и stackoverflow, и любые решения являются неполными, не обобщенными для дуги неопределенного угла или слишком сложными для меня.

Есть ли у кого-нибудь код javascript или псевдокод, который бы помог? Ранее я задавал аналогичный вопрос, но неправильно ссылался на кривую Безье как квадратичную, когда мне нужна кубическая кривая Безье.

ответ

2

Кубический подход Безье окружной дуги, определяемый координатами начальной и конечной точек, центром и радиусом окружности - (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) 

Координаты контрольных точек (к - неизвестно но фактор):

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 код (не проверяет входные данные, не обрабатывает дополнительные случаи), и это результат: enter image description here

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; 
+0

Спасибо, MBo, это именно то, что я искал. Преобразование в javascript было простым, и оно отлично работает. Извините за путаницу в моем предыдущем посте. – Pat

+0

Для получения более общих объяснений см. Также http://pomax.github.io/bezierinfo/#circles_cubic, который дает прямые формулы для контрольных точек на основе вашего известного угла дуги φ –