У нас есть начальная точка (x, y) и радиус окружности. Также существует движок, который может создавать путь из точек кривой Безье.
Как создать круг с помощью кривых Безье?
Ответы:
Как уже было сказано: не существует точного представления круга с помощью кривых Безье.
Чтобы завершить другие ответы: для кривой Безье с n
сегментами оптимальное расстояние до контрольных точек в том смысле, что середина кривой лежит на самой окружности, составляет (4/3)*tan(pi/(2n))
.
Так что для 4 баллов это так (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831
.
Охватывается в 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/
Обратите внимание, что некоторые браузеры используют кривые Безье для своей дуги рисования холста, Chrome использует (в настоящее время) четырехсекторный подход, а Safari - восьмисекторный подход, разница заметна только при высоком разрешении, из-за этого 0,0273%, а также действительно видимый только тогда, когда дуги нарисованы параллельно и не в фазе, вы заметите, что дуги колеблются от истинной окружности. Эффект также более заметен, когда кривая анимируется вокруг своего радиального центра, радиус 600 пикселей обычно является размером, в котором это будет иметь значение.
Некоторые API рисования не имеют истинного рендеринга дуги, поэтому они также используют кривые Безье, например, платформа Flash не имеет API рисования дуги, поэтому любые платформы, которые предлагают дуги, обычно используют тот же подход кривой Безье.
Обратите внимание, что движки SVG в браузерах могут использовать другой метод рисования.
Какую бы платформу вы ни пытались использовать, стоит проверить, как выполняется рисование дуги, чтобы вы могли предсказать подобные визуальные ошибки и адаптироваться.
Ответы на вопрос очень хорошие, поэтому добавить особо нечего. Вдохновленный этим, я начал проводить эксперимент, чтобы визуально подтвердить решение, начав с четырех кривых Безье, сократив количество кривых до одной. Удивительно, но я обнаружил, что с тремя кривыми Безье круг выглядел для меня достаточно хорошо , но конструкция немного сложна. На самом деле я использовал Inkscape, чтобы поместить черную аппроксимацию Безье шириной в 1 пиксель на красный круг шириной в 3 пикселя (созданный Inkscape). Для пояснения я добавил синие линии и поверхности, показывающие ограничивающие рамки кривых Безье.
Чтобы увидеть себя, представляю свои результаты:
График с 1 кривой (который для полноты картины выглядит как капля, зажатая в углу):
(Я хотел поместить сюда SVG или PDF, но это не поддерживается)
Уже много ответов, но я нашел небольшую онлайн-статью с очень хорошей кубической аппроксимацией круга Безье. В единицах окружности c = 0,55191502449, где c - расстояние от точек пересечения оси по касательным к контрольным точкам.
В качестве одного квадранта для единичной окружности, где две средние координаты являются контрольными точками. (0,1),(c,1),(1,c),(1,0)
Радиальная погрешность составляет всего 0,019608%, поэтому мне просто пришлось добавить ее в этот список ответов.
Статью можно найти здесь Приближаем окружность кубическими кривыми Безье
Это невозможно. Безье - это кубик (по крайней мере ... наиболее часто используемый). Круг не может быть точно выражен кубикой, потому что круг содержит квадратный корень в своем уравнении. Как следствие, вы должны приблизиться.
Для этого вам нужно разделить свой круг на n-танты (например, квадранты, октанты). Для каждого n-танта вы используете первую и последнюю точку как первую и последнюю на кривой Безье. Многоугольник Безье требует двух дополнительных точек. Чтобы быть быстрым, я бы взял касательные к окружности для каждой крайней точки n-танта и выбрал две точки как пересечение двух касательных (так, чтобы в основном ваш многоугольник Безье был треугольником). Увеличьте количество n-значений, чтобы соответствовать вашей точности.
Другие ответы охватывают тот факт, что настоящий круг невозможен. Этот файл SVG представляет собой аппроксимацию с использованием квадратичных кривых Безье и является наиболее близким из возможных: http://en.wikipedia.org/wiki/File:Circle_and_quadratic_bezier.svg
Вот один с кубическими кривыми Безье: http://en.wikipedia.org/wiki/File:Circle_and_cubic_bezier.svg
Людям, которые просто ищут код:
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 полукруга.
Я не уверен, стоит ли мне открывать новый вопрос, поскольку речь идет об приближении, но меня интересует общая формула для получения контрольных точек для Безье любой степени, и я считаю, что она вписывается в этот вопрос. Все решения, которые я нашел в сети, предназначены только для кубических кривых или платные, или я даже не понимаю (я не очень хорошо разбираюсь в математике). Поэтому я решил попробовать решить эту проблему самостоятельно. Я изучал расстояние контрольной точки от центра круга в зависимости от заданного угла и до сих пор обнаружил, что:
Где N
- количество контрольных точек для одиночной кривой, а α
- угол дуги окружности.
Для квадратичной кривой ее можно упростить до. l ≈ r + r * PI*0.1 * pow(α/90, 2)
Это PI*0.1
скорее предположение - я не рассчитывал идеальное значение, но оно довольно близко. Это достаточно хорошо работает для кривой с 1-2 контрольными точками, что дает ошибку радиуса около 0,2% для кубической кривой. Для кривых более высоких степеней заметна потеря точности. С тремя контрольными точками кривая похожа на квадратичную, поэтому, очевидно, я что-то упускаю, но не могу понять, и этот метод в целом соответствует моим потребностям. Вот демо .
Извините, что вернул его из мертвых, но я нашел этот пост вместе с этой страницей очень полезным в разработке расширяемой формулы.
По сути, вы можете создать близкий круг, используя невероятно простую формулу, которая позволяет использовать любое количество кривых Безье более 4: Distance = radius * stepAngle / 3
Где Distance
- расстояние между контрольной точкой Безье и ближайшим концом дуги, радиус - это радиус radius
круга, а stepAngle
это угол между двумя концами дуги, представленный как 2π / (количество кривых).
Итак, чтобы попасть в цель одним выстрелом: Distance = radius * 2π / (the number of curves) / 3
Distance = (4/3)*tan(pi/2n)
. Для большого количества дуг это почти то же самое, потому что tan(pi/2)~pi/2n
, но, например, для n=4
(что является наиболее часто используемым случаем) ваша формула дает, Distance=0.5235...
но оптимальная Distance=0.5522...
(поэтому у вас есть ошибка ~ 5%).
Это тяжелое приближение, которое будет выглядеть разумным или ужасным в зависимости от разрешения и точности, но я использую sqrt (2) / 2 x radius в качестве контрольных точек. Я прочитал довольно длинный текст о том, как выводится это число, и его стоит прочитать, но приведенная выше формула является быстрой и грязной.