Bagaimana cara membuat lingkaran dengan kurva Bézier?


Jawaban:


139

Seperti yang sudah dikatakan: tidak ada representasi yang tepat dari lingkaran menggunakan kurva Bezier.

Untuk melengkapi jawaban lain: untuk kurva Bezier dengan nsegmen jarak optimal ke titik kontrol, dalam arti bahwa bagian tengah kurva terletak pada lingkaran itu sendiri (4/3)*tan(pi/(2n)).

rumus untuk n segmen

Jadi untuk 4 poin (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

Kasus 4 poin


2
Dengan jarak optimal, jenis metrik apa yang Anda optimalkan? Seperti yang ditunjukkan dalam Perkiraan lingkaran dengan kurva Bézier kubik , penyimpangan maksimum serendah mungkin dicapai dengan nilai yang berbeda. Dapatkah Anda memberikan beberapa tautan yang menjelaskan arti "optimal" dalam kasus Anda, atau bagaimana rumus tersebut diturunkan?
Suma

1
@Suma ini tidak optimal untuk jarak tertentu. Hal ini optimal untuk memiliki tengah kurva pada lingkaran. Dan tentunya bisa dibuat lebih baik lagi jika menempatkan kriteria lain.
Kpym

2
BAIK. Saya akan mencoba menyusun ulang: "jarak ke titik kontrol sedemikian rupa sehingga bagian tengah kurva terletak pada lingkaran itu sendiri". Saya melihat ini sebagai keputusan yang valid (cukup baik dan mudah dihitung), tetapi saya tidak akan menyebutnya optimal (setidaknya tidak tanpa menulis dalam arti optimal).
Suma

1
Ya, karena yang ini memiliki deviasi maksimal + 0,027% dan deviasi min -0 vs lingkaran sebenarnya. Hanya akan lebih besar dari lingkaran nyata pendekatan perbaikan yang lebih baik dilakukan dengan memindahkan C setengah dari 0,027%. Jika Anda menginginkan titik tengah pada lingkaran, ini pasti cara untuk melakukannya.
Tatarize

2
@ legends2k Saya menggunakan LaTeX dengan TikZ untuk menghasilkan PDF yang kemudian saya ubah menjadi PNG.
Kpym

35

Tercakup dalam comp.graphics.faq

Kutipan:

Subjek 4.04: Bagaimana cara memasang kurva Bezier ke lingkaran?

Yang cukup menarik, kurva Bezier bisa mendekati lingkaran tetapi tidak pas dengan lingkaran. Perkiraan umum adalah dengan menggunakan empat bezer untuk memodelkan lingkaran, masing-masing dengan titik kontrol jarak d = r * 4 * (akar (2) -1) / 3 dari titik akhir (di mana r adalah jari-jari lingkaran), dan di arah yang bersinggungan dengan lingkaran di titik akhir. Ini akan memastikan titik tengah Beziers berada di lingkaran, dan turunan pertamanya berkelanjutan.
Kesalahan radial dalam perkiraan ini akan menjadi sekitar 0,0273% dari jari-jari lingkaran.

Michael Goldapp, "Perkiraan busur lingkaran oleh polinomial kubik" Desain Geometris Berbantuan Komputer (# 8 1991 hlm.227-238)

Tor Dokken dan Morten Daehlen, "Perkiraan yang Baik dari lingkaran dengan kurva Bezier kontinu kelengkungan" Computer Aided Geometric Design (# 7 1990 hlm. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (artikel tidak gratis)

Lihat juga artikel non-paywall di http://spencermortensen.com/articles/bezier-circle/

Browser dan Elemen Kanvas.

Perhatikan bahwa beberapa browser menggunakan kurva Bezier ke busur gambar kanvas mereka, Chrome menggunakan (saat ini) pendekatan 4 sektor dan Safari menggunakan pendekatan 8 sektor, perbedaannya hanya terlihat pada resolusi tinggi, karena itu 0,0273%, dan juga hanya benar-benar terlihat ketika busur digambar secara paralel dan keluar dari fase, Anda akan melihat busur berosilasi dari lingkaran sebenarnya. Efeknya juga lebih terlihat saat kurva dianimasikan di sekitar pusat radial, radius 600px biasanya merupakan ukuran yang akan membuat perbedaan.

API gambar tertentu tidak memiliki rendering busur yang sebenarnya sehingga mereka juga menggunakan kurva Bezier, misalnya platform Flash tidak memiliki api gambar busur, sehingga kerangka kerja apa pun yang menawarkan busur umumnya menggunakan pendekatan kurva Bezier yang sama.

Perhatikan bahwa mesin SVG dalam browser mungkin menggunakan metode gambar yang berbeda.

Platform lain

Platform apa pun yang Anda coba gunakan, ada baiknya memeriksa untuk melihat bagaimana menggambar busur dilakukan, sehingga Anda dapat memprediksi kesalahan visual seperti ini, dan beradaptasi.


Terima kasih, saya akan menggantinya.
ocodo

31

Jawaban atas pertanyaan itu sangat bagus, jadi tidak banyak yang bisa ditambahkan. Terinspirasi oleh hal itu, saya mulai membuat percobaan untuk mengonfirmasi solusi secara visual , dimulai dengan empat kurva Bézier, mengurangi jumlah kurva menjadi satu. Hebatnya saya menemukan bahwa dengan tiga kurva Bézier lingkaran tersebut terlihat cukup bagus untuk saya, tetapi konstruksinya agak rumit. Sebenarnya saya menggunakan Inkscape untuk menempatkan perkiraan Bézier selebar 1 piksel hitam di atas lingkaran merah selebar 3 piksel (seperti yang diproduksi oleh Inkscape). Untuk klarifikasi, saya menambahkan garis dan permukaan biru yang menunjukkan kotak pembatas kurva Bézier.

Untuk melihat diri Anda sendiri, saya sedang mempresentasikan hasil saya:

Grafik 1 kurva (yang terlihat seperti setetes terjepit di pojok, hanya untuk kelengkapan):masukkan deskripsi gambar di sini

Grafik 2 kurva:masukkan deskripsi gambar di sini

Grafik 3 kurva:masukkan deskripsi gambar di sini

Grafik 4 kurva: masukkan deskripsi gambar di sini

(Saya ingin meletakkan SVG atau PDF di sini, tetapi itu tidak didukung)


1
Sekarang, svg dapat dimasukkan sebagai cuplikan kode html. Lihat contoh jawaban ini: stackoverflow.com/a/32162431
TS

1
@ TS: Ketika saya mencoba mengganti grafik dengan SVG yang saya miliki, saya menyadari bahwa saya kehilangan yang memiliki stik USB yang telah dicuri pada awal tahun ini. Jika waktu mengizinkan, saya akan mencoba membuatnya kembali segera. Namun jika SVG dapat ditambahkan sebagai kode XML (dan tidak ditampilkan sebagai grafik), hal itu tidak masuk akal di sini.
U. Windl

Jika browser Anda mendukung svg, maka gambar akan ditampilkan segera setelah Anda mengklik "Jalankan Cuplikan Kode" (tampaknya tombol itu tidak tersedia di stackoverflow versi seluler ...). Lihat jawaban yang saya tautkan.
TS

1
@ TS: Untuk file yang lebih panjang itu IMHO terlalu jelek.
U. Windl

9

Banyak jawaban sudah tetapi saya menemukan artikel online kecil dengan perkiraan kubik bezier lingkaran yang sangat bagus. Dalam hal lingkaran satuan c = 0,55191502449 di mana c adalah jarak dari titik potong sumbu sepanjang garis singgung ke titik kontrol.

Sebagai kuadran tunggal untuk lingkaran satuan dengan dua koordinat tengah sebagai titik kontrol. (0,1),(c,1),(1,c),(1,0)

Kesalahan radial hanya 0,019608% jadi saya hanya perlu menambahkannya ke daftar jawaban ini.

Artikelnya dapat ditemukan di sini Perkiraan lingkaran dengan kurva Bézier kubik


5
Sudahkah Anda membaca risalah yang sangat bagus tentang Kurva Bezier ini oleh Mike 'Pomax' Kamermans dari Stackoverflow . Ini layak untuk dibaca! :-)
tandai

1
@markE Terima kasih banyak untuk tautan itu, itu adalah salah satu risalah "paling bagus" yang pernah saya lihat tentang subjek itu. Tidak sabar untuk mendapatkan kesempatan untuk membahasnya secara detail ..: D terima kasih ...
Blindman67

1
Jadi dengan kesalahan 0,019608%, grafik akan mendapatkan kesalahan 4 piksel ketika radius melampaui 2551 piksel dalam lingkaran daripada 0,027253% yang mengerikan di mana kita adalah kesalahan setengah piksel yang solid (di mana mesin grafis akan mengubah piksel) pada 1835 px menyebabkan kesalahan 2 piksel!
Tatarize

@Tatarize Artikel tersebut tidak menjelaskan bagaimana kesalahan diukur, dikatakan penyimpangan radial maksimum? Saya anggap kesalahan diminimalkan sepanjang kurva 0 <= t <= 1 agar sesuai dengan kuadran 0 <= pheta <= Pi / 2 pada t = 0 = 1/2 = 1 sama dengan pheta = 0 = Pi / 4 = Pi / 4 kesalahan adalah 0,019608% dan kesalahan maks pada t = ~ 0,1822 & t = ~ 0,8177 dari 0,019608% (tanda?) Tetapi pada titik-titik ini t tidak sama dengan pheta apakah kesalahan tersebut termasuk penyimpangan sudut? . 4pixels mungkin atau mungkin tidak benar. Kesalahannya mungkin varians, jadi kesalahan <2pix untuk r = 2551. Banyak pertanyaan yang perlu diselidiki
Blindman67

Saya cukup yakin setelah melihat kurva kesalahan bahwa penyesuaian yang diberikan hanya memindahkan titik ke bawah cukup untuk menyebabkan kesalahan maks di atas garis busur sama dengan kesalahan maks di bawah garis busur. Artinya kita mengubah kurva sedikit ke bawah sehingga semua kesalahan tidak positif. Penyesuaian ini berarti kita melewati garis busur 4 kali, dengan 4 titik kesalahan maksimum. Ketika garis spesifikasi asli memiliki 2 titik, yaitu pada t = 0,25 dan t = 0,75. Dengan penyesuaian harus pada t = 0,125, t = 0,375 t = 0,625 t = 0,875. Ini mengasumsikan kami menggunakan piksel solid dan bukan anti-alias yang akan berubah pada 14px.
Tatarize

8

Ini tidak mungkin. Bezier adalah kubik (setidaknya ... yang paling umum digunakan adalah). Sebuah lingkaran tidak dapat diekspresikan secara tepat dengan kubik, karena sebuah lingkaran mengandung akar kuadrat dalam persamaannya. Akibatnya, Anda harus membuat perkiraan.

Untuk melakukan ini, Anda harus membagi lingkaran Anda dalam n-tant (egquadrants, oktan). Untuk setiap n-tant, Anda menggunakan titik pertama dan terakhir sebagai titik pertama dan terakhir dari kurva Bezier. Poligon Bezier membutuhkan dua titik tambahan. Agar cepat, saya akan mengambil garis singgung lingkaran untuk setiap titik ekstrem n-tant dan memilih dua titik sebagai perpotongan dua garis singgung (sehingga pada dasarnya poligon Bezier Anda adalah segitiga). Tingkatkan jumlah n-tants agar sesuai dengan presisi Anda.


4
Itu mungkin, selama Anda menggunakan kurva bezier dalam jumlah tak terbatas, dengan panjang nol. Yang pada dasarnya adalah jumlah titik yang tak terbatas, atau lebih tepatnya hanya kurva busur.
Tatarize


7

Untuk orang yang hanya mencari kode:

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>

Ini memungkinkan untuk menggambar lingkaran yang terbuat dari 4 kurva Bezier. Ditulis dalam JS, tetapi dapat dengan mudah diterjemahkan ke bahasa lain

Catatan

Jangan gunakan kurva Bezier jika Anda perlu menggambar lingkaran menggunakan jalur SVG kecuali diharuskan melakukannya. Di jalan Anda dapat menggunakan Arcuntuk membuat 2 setengah lingkaran.

Gambar lingkaran dengan jalur busur SVG


Itu sangat membantu, terima kasih! Apa yang perlu diubah untuk menertibkan 4 segmen? Saya perlu menulis teks di sepanjang jalur, tetapi sekarang teks tersebut tersebar di sekitar 4 segmen
Alexa

1

Saya tidak yakin apakah saya harus membuka pertanyaan baru karena ini tentang perkiraan tetapi saya tertarik dengan rumus umum untuk mendapatkan poin kontrol untuk Bezier dari tingkat apa pun dan saya yakin itu cocok dengan pertanyaan ini. Semua solusi yang saya temukan di web hanya untuk kurva kubik atau berbayar atau saya bahkan tidak mengerti (saya tidak pandai matematika). Jadi saya memutuskan mencoba menyelesaikan ini sendiri. Saya mempelajari jarak titik kontrol dari pusat lingkaran tergantung pada sudut tertentu dan sejauh ini saya menemukan bahwa:

masukkan deskripsi gambar di sini

Dimana Nadalah jumlah titik kontrol untuk kurva tunggal danα merupakan sudut busur lingkaran.

Untuk kurva kuadrat, dapat disederhanakan menjadi l ≈ r + r * PI*0.1 * pow(α/90, 2) The PI*0.1agak tebakan - Saya tidak menghitung nilai sempurna tetapi cukup mendekati. Ini bekerja cukup baik untuk kurva dengan 1-2 titik kontrol yang memberikan kesalahan radius sekitar 0,2% untuk kurva kubik. Untuk kurva derajat yang lebih tinggi, kerugian akurasi terlihat. Dengan kurva 3 titik kontrol terlihat mirip dengan kuadrat jadi jelas saya melewatkan sesuatu tetapi saya tidak dapat mengetahuinya dan metode ini umumnya sesuai dengan kebutuhan saya untuk saat ini. Ini demo .


Perangkat lunak apa yang Anda gunakan untuk membuat gambar ini?
Qian Sijianhao

1
Tangkapan layar dari demo saya + panel penulisan Matematika (atau bagaimanapun namanya diterjemahkan) dari win 7 + MS Paint
Paweł Audionysos

0

Maaf untuk menghidupkan yang ini dari kematian, tetapi saya menemukan posting ini sangat membantu bersama dengan halaman ini dalam menghasilkan formula yang dapat diperluas.

Pada dasarnya, Anda dapat membuat lingkaran dekat menggunakan rumus yang sangat sederhana yang memungkinkan Anda menggunakan sejumlah kurva Bezier di atas 4: Distance = radius * stepAngle / 3

Dimana Distanceadalah jarak antara titik kendali Bezier dan ujung terdekat dari busur, jari-jari adalah radiusdari lingkaran, dan stepAnglemerupakan sudut antara 2 ujung busur yang diwakili oleh 2π / (jumlah kurva).

Jadi untuk memukulnya dalam satu tembakan: Distance = radius * 2π / (the number of curves) / 3


1
Ini bukan perkiraan terbaik dari sebuah lingkaran. Yang terbaik adalah Distance = (4/3)*tan(pi/2n). Untuk jumlah busur yang besar hampir sama karena tan(pi/2)~pi/2n, tetapi misalnya untuk n=4(yang merupakan kasus yang paling sering digunakan) rumus Anda memberikan Distance=0.5235...tetapi yang optimal adalah Distance=0.5522... (jadi Anda memiliki kesalahan ~ 5%).
Kpym

-2

Ini adalah perkiraan berat yang akan terlihat masuk akal atau mengerikan tergantung pada resolusi dan presisi tetapi saya menggunakan radius sqrt (2) / 2 x sebagai titik kontrol saya. Saya membaca teks yang agak panjang bagaimana angka itu diturunkan dan itu layak dibaca tetapi rumus di atas cepat dan kotor.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.