2014-11-05 5 views
0

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

Я могу создать срез A1 ниже как треугольник, но я не могу понять, как определить контрольные точки. Также, если я попытаюсь вырезать срез из круга в противоположном направлении, обратите внимание на то, как контрольные точки указывают в отрицательном направлении.

Итак, если я хочу срез круга с радиусом R, и я уже вычислил опорные точки, как я могу вычислить положение контрольной точки 1 и контрольной точки 2 ???

Example

+1

Когда вы говорите о кривых Безье в iOS, вы имеете в виду 'UIBezierPath'? Если вы находитесь, вы можете использовать 'bezierPathWithArcCenter: radius: startAngle: endAngle: по часовой стрелке:' делать то, что вы хотите ... –

+0

Или использовать 'addArcWithCenter: radius: startAngle: endAngle: по часовой стрелке:' добавить круговую часть к существующему который вы создаете. – Rob

+1

[Вы должны посмотреть это фантастическое объяснение того, как компьютеры рисуют кривые] (http://sploid.gizmodo.com/fantastic-explanation-of-how-computers-draw-curves-1641989231). Возможно, это поможет вам определить, как вычислить контрольные точки. – zisoft

ответ

1

Фэн Юань предложил простой метод в своей книге Windows Graphics Programming: построить дугу с радиусом 1, центрированную осью ОХ, рассчитать приближение Безье и масштабировать, переводить и поворачивать контрольные точки для необходимых параметров дуги. Вот моя реализация этого метода (в Delphi), модифицированная для больших дуг. Источники C++ можно найти где-то в Интернете, но я надеюсь, что логика понятна.

GenerateBezierArc(200, 200, 150, Pi/4, 3 * Pi/2, Pts); 
    Canvas.PolyBezier(Pts); 

результат:

enter image description here

type 
    TPointArray = array of TPoint; 

//calculates array of Bezier control points 
//for circle arc with center CX, CY and radius R 
procedure GenerateBezierArc(CX, CY, R: Integer; 
          StartAngle, SweepAngle: Double; 
          var Pts: TPointArray); 
// C-Pascal translation from Feng Yuan book, with correction of source errors 
var 
    iCurve, NCurves: Integer; 
    i: Integer; 
    x0, y0, tx, ty, sn, cs, ASweep, AStart: Double; 
    Px, Py: array [0 .. 3] of Double; 
begin 
    if SweepAngle = 0 then 
    Exit; 
    // if SweepAngle is too large, divide arc to smaller ones 
    NCurves := Ceil(Abs(SweepAngle)/(Pi/2)); 
    SetLength(Pts, 3 * NCurves + 1); 
    ASweep := SweepAngle/NCurves; 

    // calculates control points for Bezier approx. of arc with radius=1, 
    // circle center at (0,0), middle of arc at (1,0) 
    y0 := Sin(ASweep/2); 
    x0 := Cos(ASweep/2); 
    tx := (1 - x0) * 4/3; 
    ty := y0 - tx * x0/(y0 + 0.0001); 
    Px[0] := x0; 
    Py[0] := -y0; 
    Px[1] := x0 + tx; 
    Py[1] := -ty; 
    Px[2] := x0 + tx; 
    Py[2] := ty; 
    Px[3] := x0; 
    Py[3] := y0; 

    // rotation and translation of control points 
    sn := Sin(StartAngle + ASweep/2); 
    cs := Cos(StartAngle + ASweep/2); 
    Pts[0].X := CX + Round(R * (Px[0] * cs - Py[0] * sn)); 
    Pts[0].Y := CY + Round(R * (Px[0] * sn + Py[0] * cs)); 

    for iCurve := 0 to NCurves - 1 do begin 
    AStart := StartAngle + ASweep * iCurve; 
    sn := Sin(AStart + ASweep/2); 
    cs := Cos(AStart + ASweep/2); 
    for i := 1 to 3 do begin 
     Pts[i + iCurve * 3].X := CX + Round(R * (Px[i] * cs - Py[i] * sn)); 
     Pts[i + iCurve * 3].Y := CY + Round(R * (Px[i] * sn + Py[i] * cs)); 
    end; 
    end; 
end; 
0

This article дает набор кривых Безье 4, который генерирует очень близкое приближение окружности. Он делит круг на 4 четверти, и каждая кривая генерирует 1/4 круга.

Я не знаю, как вы придумали контрольные точки для произвольной дуги по кругу. Вы должны использовать триггер, чтобы найти начальную и конечную точки, но средние точки будут сложнее.

Вывод статьи:

Максимальный радиальный дрейф 0,019608% с этим приближением. Это на 28% лучше, чем стандартное приближение. Вот так получилось:

Рисунок 4. Нелинейное приближение Безье почти неотличимо от круга. Рисунок 4 был создан с использованием кривых Безье: P_0 = (0,1), P_1 = (c, 1), P_2 = (1, c), P_3 = (1,0) P_0 = (1,0) , P_1 = (1, -c), P_2 = (c, -1), P_3 = (0, -1) P_0 = (0, -1), P_1 = (-c, -1), P_3 = (-1, -c), P_4 = (-1,0) P_0 = (-1,0), P_1 = (-1, c), P_2 = (-c, 1), P_3 = (0,1) с c = 0,551915024494.

Это для единичного круга (круг в начале координат с радиусом 1). Вам нужно будет масштабировать его для других значений радиуса.

EDIT:

Если вы предполагаете, что ваша дуга всегда будет 1/4 круга или меньше, то вы можете использовать кривые Безье для 1/4 круга, и нарисуйте часть этой дуги изменяя диапазон параметра t на диапазон, меньший t = 0 -> t = 1. Вам нужно применить преобразование вращения к своим точкам, чтобы переместить их по кругу.

+0

Я даже не отдаленно понимаю эту статью. Кроме того, я не думаю, что он вычисляет контрольные точки, а только точки привязки. – user160632

+0

ОП говорит: «...Я уже вычислил опорные точки, как я могу рассчитать положение контрольной точки 1 и контрольной точки 2? »Если вы посмотрите на его иллюстрацию, контрольные точки - это две внутренние точки. Вычисление опорных точек тривиально с использованием синуса и косинус –

+0

Вы говорите об «общей формуле кубической кривой Безье» B (t) = (1-t)^3 * P_0 + 3 * (1-t)^2 * t * P_1 + 3 * (1-t) * t^2 * P_2 + t^3 * P_3, t in [0,1] Первое ограничение подразумевает, что: P_0 = (0,1), P_1 = (c, 1) , P_2 = (1, c), P_3 = (1,0) Второе ограничение дает значение c: c = (4/3) * (sqrt (2) - 1) Если мой первый якорный указатель 25,35, как я могу использовать эту формулу, чтобы получить первый conor anchorPoint 1 контрольная точка (x, y) ???? – user160632

0

В статье ссылается пост Дункан на самом деле результат для 90 градусов дуги окружности от журнальной бумаги авторства Тора Доккен (главный автор) и опубликованной в журнале «Автоматизированный геометрический дизайн» № 7 в 1990 году. Он привел два подхода для приближения дуги на 90 градусов: стандартный подход и лучший подход. Я перечислим общую формулу для «стандартного подхода» ниже и оставьте общую формулу для «лучшего подхода», так как она требует большого набора текста:

Для дуги окружности с угловым пролетом А и радиусом юнита, описанным как C (t) = (cos (t), sin (t)), где t = [0, A], хорошее кубическое приближение кривой Безье может быть получено со следующими контрольными точками:

P (0) = (1, 0),
Р (1) = (1, 0) + L (0,1),
Р (2) = (коза, Sina) - L (-sinA, коза),
P (3) = (cosA, sinA)

, где L представляет собой скаляр константа, зависящая от А, как

L = (4/3) * тангенс (A/4)

Пожалуйста, обратите внимание, что кубическая кривая Безье приближение получается таким образом, всегда интерполирует два конца точки и среднюю точку дуги окружности, а погрешность аппроксимации всегда положительна, что означает, что кубическая кривая Безье всегда «вне» дуги окружности.

Максимальная радиальная ошибка (х (т)^2 + у (т)^2 - 1) из этой простой формулы

Error_max = (4/27) * (мощность (син (А/4), 6)/мощность (cos (A/4), 2))

Если вы хотите приблизить общую дугу окружности (любой угол и радиус радиуса) в пределах определенного допуска, вы можете использовать эту формулу для вычислите, сколько сегментов вам нужно разбить круговую дугу и приблизить каждый сегмент дуги кубической кривой Безье. Так как эта кубическая кривая Безье будет оценивать конечные точки и конечные наклоны, все полученные кривые Безье будут соединены плавно вместе.

Смежные вопросы