Как создать круг с кривыми Безье?


101

У нас есть начальная точка (x, y) и радиус окружности. Также существует движок, который может создавать путь из точек кривой Безье.

Как создать круг с помощью кривых Безье?


Ответы:


139

Как уже было сказано: не существует точного представления круга с помощью кривых Безье.

Чтобы завершить другие ответы: для кривой Безье с nсегментами оптимальное расстояние до контрольных точек в том смысле, что середина кривой лежит на самой окружности, составляет (4/3)*tan(pi/(2n)).

формула для n сегментов

Так что для 4 баллов это так (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

4-х балльный случай


2
Какие показатели вы оптимизируете при оптимальном расстоянии? Как показано в Приближении круга с кубическими кривыми Безье , наименьший возможный максимальный дрейф достигается за счет другого значения. Можете ли вы предоставить ссылку, определяющую, что означает «оптимальный» в вашем случае или как это получилось из формулы?
Suma

1
@Suma это не оптимально для некоторого расстояния. Это оптимальное иметь середину кривой на окружности. И, конечно, можно улучшить, если поставить другие критерии.
Kpym

2
ХОРОШО. Попробую перефразировать: «расстояние до контрольных точек такое, чтобы середина кривой лежала на самой окружности». Я считаю это правильным решением (достаточно хорошим и легко вычисляемым), но я бы не назвал его оптимальным (по крайней мере, не написав, в каком смысле оно оптимально).
Suma

1
Да, так как у этого есть максимальное отклонение + 0,027% и минимальное отклонение -0 от истинного круга. Это только когда-либо больше, чем реальный круг, лучшее улучшенное приближение достигается путем перемещения C на половину 0,027%. Если вам нужны средние точки на круге, это, безусловно, способ сделать это.
Tatarize

2
@ legends2k Я использую LaTeX с TikZ для создания PDF-файла, который затем конвертирую в PNG.
Kpym 06

35

Охватывается в comp.graphics.faq

Отрывок:

Тема 4.04: Как разместить кривую Безье на окружности?

Интересно, что кривые Безье могут приближаться к кругу, но не идеально вписываются в круг. Распространенным приближением является использование четырех кривых Безье для моделирования круга, каждая из которых имеет контрольные точки на расстоянии d = r * 4 * (sqrt (2) -1) / 3 от конечных точек (где r - радиус круга), а в направление, касательное к окружности в конечных точках. Это гарантирует, что средние точки кривой Безье находятся на окружности, а первая производная будет непрерывной.
Радиальная ошибка в этом приближении будет около 0,0273% от радиуса круга.

Майкл Голдапп, «Аппроксимация дуг окружности кубическими многочленами» Компьютерное геометрическое проектирование (№ 8, 1991, стр. 227-238)

Тор Доккен и Мортен Дэлен, "Хорошие аппроксимации окружностей непрерывными по кривизне кривыми Безье". Компьютерное геометрическое проектирование (№ 7, 1990, стр. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (платная статья)

Также см. Статью без платного доступа по адресу http://spencermortensen.com/articles/bezier-circle/

Браузеры и элемент Canvas.

Обратите внимание, что некоторые браузеры используют кривые Безье для своей дуги рисования холста, Chrome использует (в настоящее время) четырехсекторный подход, а Safari - восьмисекторный подход, разница заметна только при высоком разрешении, из-за этого 0,0273%, а также действительно видимый только тогда, когда дуги нарисованы параллельно и не в фазе, вы заметите, что дуги колеблются от истинной окружности. Эффект также более заметен, когда кривая анимируется вокруг своего радиального центра, радиус 600 пикселей обычно является размером, в котором это будет иметь значение.

Некоторые API рисования не имеют истинного рендеринга дуги, поэтому они также используют кривые Безье, например, платформа Flash не имеет API рисования дуги, поэтому любые платформы, которые предлагают дуги, обычно используют тот же подход кривой Безье.

Обратите внимание, что движки SVG в браузерах могут использовать другой метод рисования.

Другие платформы

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


Спасибо, подставлю.
ocodo

31

Ответы на вопрос очень хорошие, поэтому добавить особо нечего. Вдохновленный этим, я начал проводить эксперимент, чтобы визуально подтвердить решение, начав с четырех кривых Безье, сократив количество кривых до одной. Удивительно, но я обнаружил, что с тремя кривыми Безье круг выглядел для меня достаточно хорошо , но конструкция немного сложна. На самом деле я использовал Inkscape, чтобы поместить черную аппроксимацию Безье шириной в 1 пиксель на красный круг шириной в 3 пикселя (созданный Inkscape). Для пояснения я добавил синие линии и поверхности, показывающие ограничивающие рамки кривых Безье.

Чтобы увидеть себя, представляю свои результаты:

График с 1 кривой (который для полноты картины выглядит как капля, зажатая в углу):введите описание изображения здесь

График с двумя кривыми:введите описание изображения здесь

График с 3 кривыми:введите описание изображения здесь

Четырехкривый график: введите описание изображения здесь

(Я хотел поместить сюда SVG или PDF, но это не поддерживается)


1
К настоящему времени svg может быть включен как фрагмент кода html. См., Например, этот ответ: stackoverflow.com/a/32162431
TS

1
@TS: Когда я попытался заменить графику имеющимися у меня SVG, я понял, что потерял те, у которых был украден USB-накопитель в начале этого года. Если позволит время, постараюсь в ближайшее время их воссоздать. Однако, если SVG может быть добавлен в виде кода XML (и не отображается в виде графики), это не имеет здесь особого смысла.
U. Windl

Если ваш браузер поддерживает svg, изображения будут отображаться, как только вы нажмете «Выполнить фрагмент кода» (очевидно, эта кнопка недоступна в мобильной версии stackoverflow ...). См. Ответ, который я связал.
TS

1
@TS: Для более длинных файлов это слишком некрасиво ИМХО.
U. Windl

9

Уже много ответов, но я нашел небольшую онлайн-статью с очень хорошей кубической аппроксимацией круга Безье. В единицах окружности c = 0,55191502449, где c - расстояние от точек пересечения оси по касательным к контрольным точкам.

В качестве одного квадранта для единичной окружности, где две средние координаты являются контрольными точками. (0,1),(c,1),(1,c),(1,0)

Радиальная погрешность составляет всего 0,019608%, поэтому мне просто пришлось добавить ее в этот список ответов.

Статью можно найти здесь Приближаем окружность кубическими кривыми Безье


5
Вы читали этот отличный трактат Майка «Помакса» Камерманса из Stackoverflow о кривых Безье . Его стоит прочитать! :-)
markE 02

1
@markE Большое спасибо за эту ссылку, это один из «самых превосходных» трактатов, которые я когда-либо видел по этой теме. Не могу дождаться, чтобы получить шанс подробно изучить это ..: D, спасибо ...
Blindman67

1
Таким образом, с ошибкой 0,019608% графика будет получать 4 пикселя с ошибкой, когда радиус превышает 2551 пиксель по кругу, а не те ужасные 0,027253%, где мы имеем твердую половину пикселя ошибки (где графический движок изменит пиксель) на 1835 пикселей, что приводит к ошибке 2 пикселей!
Tatarize 01

@Tatarize В статье не уточняется, как измерялась погрешность, там указано максимальное радиальное смещение? Я предполагаю, что ошибка минимизирована вдоль кривой 0 <= t <= 1, чтобы соответствовать квадранту 0 <= pheta <= Pi / 2 при t = 0 = 1/2 = 1 равно pheta = 0 = Pi / 4 = Pi / 4 ошибка составляет 0,019608%, а максимальная ошибка при t = ~ 0,1822 & t = ~ 0,8177 0,019608% (знаки?), Но в этих точках t не равно pheta, включает ли ошибка угловой дрейф? . 4 пикселя могут быть правильными, а могут и нет. Ошибка может быть дисперсией, поэтому ошибка <2pix для r = 2551. Множество вопросов, которые потребуют исследования
Blindman67

Я почти уверен, что, посмотрев на кривую ошибок, данная регулировка просто перемещает точку вниз настолько, чтобы максимальная ошибка над линией дуги равнялась максимальной ошибке под линией дуги. То есть мы немного изменяем кривую вниз, чтобы ошибка не была положительной. Эта настройка означает, что мы пересекаем дугу 4 раза с 4 точками максимальной ошибки. Когда исходная заданная линия имела 2 точки, а именно при t = 0,25 и t = 0,75. С поправками оно должно быть при t = 0,125, t = 0,375 t = 0,625 t = 0,875. Это предполагает, что мы используем сплошные пиксели, а не сглаживание, которое изменится на 14 пикселей.
Tatarize 01

8

Это невозможно. Безье - это кубик (по крайней мере ... наиболее часто используемый). Круг не может быть точно выражен кубикой, потому что круг содержит квадратный корень в своем уравнении. Как следствие, вы должны приблизиться.

Для этого вам нужно разделить свой круг на n-танты (например, квадранты, октанты). Для каждого n-танта вы используете первую и последнюю точку как первую и последнюю на кривой Безье. Многоугольник Безье требует двух дополнительных точек. Чтобы быть быстрым, я бы взял касательные к окружности для каждой крайней точки n-танта и выбрал две точки как пересечение двух касательных (так, чтобы в основном ваш многоугольник Безье был треугольником). Увеличьте количество n-значений, чтобы соответствовать вашей точности.


4
Это возможно, если вы используете бесконечное количество кривых Безье нулевой длины. По сути, это бесконечное количество точек или, скорее, просто дугообразная кривая.
Tatarize

7

Другие ответы охватывают тот факт, что настоящий круг невозможен. Этот файл SVG представляет собой аппроксимацию с использованием квадратичных кривых Безье и является наиболее близким из возможных: http://en.wikipedia.org/wiki/File:Circle_and_quadratic_bezier.svg

Вот один с кубическими кривыми Безье: http://en.wikipedia.org/wiki/File:Circle_and_cubic_bezier.svg


7

Людям, которые просто ищут код:

https://jsfiddle.net/nooorz24/2u9forep/12/

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY) {
    ctx.beginPath();
    ctx.moveTo(
        centerX - (sizeX),
        centerY - (0)
    );
    ctx.bezierCurveTo(
        centerX - (sizeX),
        centerY - (0.552 * sizeY),
        centerX - (0.552 * sizeX),
        centerY - (sizeY),
        centerX - (0),
        centerY - (sizeY)
    );
    ctx.stroke();
}

function drawBezierOval(centerX, centerY, sizeX, sizeY) {
    drawBezierOvalQuarter(centerX, centerY, -sizeX, sizeY);
    drawBezierOvalQuarter(centerX, centerY, sizeX, sizeY);
    drawBezierOvalQuarter(centerX, centerY, sizeX, -sizeY);
    drawBezierOvalQuarter(centerX, centerY, -sizeX, -sizeY);
}

function drawBezierCircle(centerX, centerY, size) {
    drawBezierOval(centerX, centerY, size, size)
}

drawBezierCircle(200, 200, 64)
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

Это позволяет нарисовать круг, состоящий из 4 кривых Безье. Написано на JS, но может быть легко переведено на любой другой язык.

Заметка

Не используйте кривые Безье, если вам нужно нарисовать круг с использованием пути SVG, если это не требуется. В пути вы можете Arcсоздать 2 полукруга.

Рисование окружности с помощью дуги SVG


Это очень полезно, спасибо! Что нужно изменить, чтобы привести в порядок 4 сегмента? Мне нужно написать текст вдоль пути, но теперь он разбросан по 4 сегментам
Алекса

1

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

введите описание изображения здесь

Где N- количество контрольных точек для одиночной кривой, а α- угол дуги окружности.

Для квадратичной кривой ее можно упростить до. l ≈ r + r * PI*0.1 * pow(α/90, 2) Это PI*0.1скорее предположение - я не рассчитывал идеальное значение, но оно довольно близко. Это достаточно хорошо работает для кривой с 1-2 контрольными точками, что дает ошибку радиуса около 0,2% для кубической кривой. Для кривых более высоких степеней заметна потеря точности. С тремя контрольными точками кривая похожа на квадратичную, поэтому, очевидно, я что-то упускаю, но не могу понять, и этот метод в целом соответствует моим потребностям. Вот демо .


Какое программное обеспечение вы используете для создания этого изображения?
Qian Sijianhao 01

1
Скриншот из моей демонстрации + панель для письма по математике (или, как переводится название) из win 7 + MS Paint
Paweł Audionysos

0

Извините, что вернул его из мертвых, но я нашел этот пост вместе с этой страницей очень полезным в разработке расширяемой формулы.

По сути, вы можете создать близкий круг, используя невероятно простую формулу, которая позволяет использовать любое количество кривых Безье более 4: Distance = radius * stepAngle / 3

Где Distance- расстояние между контрольной точкой Безье и ближайшим концом дуги, радиус - это радиус radiusкруга, а stepAngleэто угол между двумя концами дуги, представленный как 2π / (количество кривых).

Итак, чтобы попасть в цель одним выстрелом: Distance = radius * 2π / (the number of curves) / 3


1
Это не лучшее приближение круга. Самый лучший Distance = (4/3)*tan(pi/2n). Для большого количества дуг это почти то же самое, потому что tan(pi/2)~pi/2n, но, например, для n=4(что является наиболее часто используемым случаем) ваша формула дает, Distance=0.5235...но оптимальная Distance=0.5522... (поэтому у вас есть ошибка ~ 5%).
Kpym 09

-2

Это тяжелое приближение, которое будет выглядеть разумным или ужасным в зависимости от разрешения и точности, но я использую sqrt (2) / 2 x radius в качестве контрольных точек. Я прочитал довольно длинный текст о том, как выводится это число, и его стоит прочитать, но приведенная выше формула является быстрой и грязной.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.