Як створити коло з кривими Безьє?


99

У нас є початкова точка (x, y) і радіус кола. Існує також механізм, який може створити шлях із точок кривої Безьє.

Як я можу створити коло за допомогою кривих Безьє?


Відповіді:


138

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

Завершити інші відповіді: для кривої Безьє з nвідрізками є оптимальна відстань до контрольних точок, в тому сенсі, що середина кривої лежить на самому колі (4/3)*tan(pi/(2n)).

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

Отже, за 4 бали це (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

4-бальна справа


2
Яку метрику ви оптимізуєте за оптимальної відстані? Як показано в Приблизному колі з кубічними кривими Безьє , мінімально можливий максимальний дрейф досягається за рахунок іншого значення. Чи можете ви надати посилання, що визначає, що означає "оптимальне" у вашому випадку, або як це випливає з формули?
Сума

1
@Suma це не є оптимальним для певної відстані. Це оптимальне мати середину кривої на окружності. І, звичайно, це можна зробити кращим, якщо поставити інші критерії.
Kpym

2
ГАРАЗД. Я спробую перефразувати: "відстань до контрольних точок така, що середина кривої лежить на самому колі". Я розглядаю це як дійсне рішення (досить добре і легке для обчислення), але я б не назвав його оптимальним (принаймні, не написавши, в якому сенсі це є оптимальним).
Сума

1
Так, оскільки це має максимальне відхилення + 0,027% та мінімальне відхилення -0 проти справжнього кола. Це лише більше, ніж реальне коло, краще покращене наближення здійснюється переміщенням C на половину 0,027%. Якщо ви хочете, щоб середини кола були, це, звичайно, спосіб це зробити.
Татарізувати

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

34

Висвітлено у 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 використовує (в даний час) 4-секторний підхід, а Safari використовує 8-секторний підхід, різниця помітна лише при високій роздільній здатності, із-за цього 0,0273%, а також по-справжньому видно лише тоді, коли дуги намальовані паралельно та поза фазою, ви помітите, що дуги коливаються від справжнього кола. Ефект також помітніший, коли крива анімує навколо свого радіального центру, радіус 600px - це, як правило, розмір, де це може змінити ситуацію.

Деякі API малювання не мають справжнього рендерингу дуги, тому вони також використовують криві Безьє, наприклад, платформа Flash не має API дугового малювання, тому будь-які фреймворки, що пропонують дуги, зазвичай використовують той самий підхід кривої Безьє.

Зверніть увагу, що двигуни SVG у браузерах можуть використовувати інший спосіб малювання.

Інші платформи

Незалежно від платформи, яку ви намагаєтесь використовувати, варто перевірити, як виконується дугоподібне малювання, щоб ви могли передбачити такі візуальні помилки та адаптуватись.


Дякую, я підставляю.
ocodo

31

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

Щоб побачити себе, я представляю свої результати:

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

2-кривий графік:введіть тут опис зображення

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

4-кривий графік: введіть тут опис зображення

(Я хотів помістити сюди SVG або PDF, але це не підтримується)


1
Наразі svg можна включити як фрагмент коду html. Дивіться, наприклад, цю відповідь: stackoverflow.com/a/32162431
TS

1
@TS: Коли я спробував замінити графіку на SVG-файли, які я мав, я зрозумів, що втратив їх із USB-накопичувачем, який було вкрадено на початку цього року. Якщо дозволяє час, я спробую їх відтворити найближчим часом. Однак якщо SVG можна додати як XML-код (і він не відображається як графіка), це не має великого сенсу тут.
У. Віндл

Якщо ваш браузер підтримує svg, то зображення відображаються, як тільки ви натискаєте "Запустити фрагмент коду" (очевидно, ця кнопка недоступна в мобільній версії stackoverflow ...). Дивіться у відповіді, яку я зв’язав.
TS

1
@TS: Для довших файлів це занадто негарно IMHO.
У. Віндл

9

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

Як єдиний квадрант для одиничного кола з двома середніми координатами, які є контрольними точками. (0,1),(c,1),(1,c),(1,0)

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

Статтю можна знайти тут Орієнтовне коло з кубічними кривими Безьє


5
Чи читали ви цей чудовий трактат про Криві Безьє від Майка 'Помакса' Камерманса Stackoverflow . Це варто прочитати! :-)
markE

1
@markE Щиро дякую за це посилання, це один із "найкращих" трактатів, які я бачив на цю тему коли-небудь. Не можу дочекатися, щоб отримати шанс детально розглянути це ...: D, дякую ...
Blindman67

1
Отже, з помилкою 0,019608%, графіка отримає 4 пікселі помилки, коли радіус перевищує 2551 піксель по колу, а не тих жахливих 0,027253%, де ми маємо суцільний півпіксель помилки (де графічний движок змінить піксель) у 1835 px, спричиняючи помилку 2 пікселів!
Татарізувати

@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 не дорівнює феті, чи включає похибка кутовий дрейф? . 4пікселі можуть бути неправильними, а можуть і не бути. Помилка може бути дисперсією, отже, помилка <2пікс для r = 2551. Багато питань, які потребують розслідування
Blindman67,

Я майже впевнений, подивившись на криву помилок, що дане коригування просто зміщує точку вниз настільки, щоб максимальна помилка над лінією дуги дорівнювала максимальній помилці нижче лінії дуги. Це означає, що ми змінюємо криву трохи вниз, тому вся помилка не є позитивною. Це налаштування означає, що ми перетинаємо лінію дуги 4 рази, з 4 точками максимальної похибки. Коли вихідна специфікована лінія мала 2 точки, а саме при t = .25 та t = .75. З регулюванням воно має бути на t = .125, t = .375 t = .625 t = .875. Це передбачає, що ми використовуємо суцільні пікселі, а не згладжування, які змінюватимуться на 14 пікселів.
Татарізувати

8

Це неможливо. Безьє - це кубік (принаймні ... найчастіше використовується). Коло не можна точно виразити кубічним, оскільки коло містить у своєму рівнянні квадратний корінь. Як наслідок, вам доведеться наблизити.

Для цього вам потрібно розділити своє коло на n-танти (наприклад, квадранти, октанти). Для кожного n-танта ви використовуєте першу і останню точки як першу і останню криві Безьє. Багатокутник Безьє вимагає двох додаткових точок. Щоб бути швидким, я б відвів дотичні до кола для кожної крайньої точки n-танта і вибрав дві точки як перетину двох дотичних (так, щоб ваш багатокутник Безьє в основному був трикутником). Збільште кількість n-тантів відповідно до вашої точності.


4
Це можливо, якщо ви використовуєте нескінченну кількість кривих Безьє, нульової довжини. Що в основному є нескінченною кількістю точок, точніше просто дуговою кривою.
Татарізувати

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, але його легко перекласти на будь-яку іншу мову


Це дуже корисно, дякую! Що потрібно змінити, щоб привести 4 сегменти в порядок? Мені потрібно писати текст по контуру, але зараз він розкиданий навколо 4 сегментів
Alexa

1

Я не впевнений, чи слід мені відкривати нове питання, оскільки мова йде про наближення, але мене цікавить загальна формула, щоб отримати контрольні точки для Безьє будь-якого ступеня, і я вважаю, що це вписується в це питання. Усі рішення, які я знайшов в Інтернеті, стосуються лише кубічних кривих або платні, або я навіть не розумію (я не дуже добре володію математикою). Тому я вирішив спробувати вирішити це самостійно. Я вивчав відстань контрольної точки від центру кола залежно від даного кута і до цього часу виявив, що:

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

Де Nчисло контрольних точок для однієї кривої і αкут дуги кола.

Для квадратичної кривої її можна спростити до: l ≈ r + r * PI*0.1 * pow(α/90, 2) Це PI*0.1швидше здогадка - я не розрахував ідеальне значення, але це досить близько. Це працює досить добре для кривої з 1-2 контрольними точками, що дає похибку радіусу близько 0,2% для кубічної кривої. Для кривих вищого ступеня помітна втрата точності. Крива з 3 контрольними точками виглядає схожою на квадратичну, тому, очевидно, я щось пропускаю, але я не можу це зрозуміти, і цей метод наразі відповідає моїм потребам. Ось демо .


Яке програмне забезпечення ви використовуєте для створення цього зображення?
Цянь Сіцзяньхао,

1
Знімок екрану з моєї демонстрації + панелі математики (або, як би назва не перекладалася) з win 7 + MS Paint
Павел Аудіонісос,

0

Вибачте, що поверну це з мертвих, але я знайшов цю публікацію дуже корисною разом із цією сторінкою при розробці розширюваної формули.

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

Де Distanceвідстань між контрольною точкою Безьє та найближчим кінцем дуги, радіус - це radiusокружність, а stepAngleце кут між 2 кінцями дуги, як представлено 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

-2

Це важке наближення, яке буде виглядати розумно або жахливо залежно від роздільної здатності та точності, але я використовую sqrt (2) / 2 x радіус як свої контрольні точки. Я прочитав досить довгий текст, як виводиться це число, і його варто прочитати, але формула вище - швидка і брудна.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.