Bézier eğrileriyle daire nasıl oluşturulur?


101

Bir başlangıç ​​noktamız (x, y) ve bir daire yarıçapımız var. Bézier eğri noktalarından bir yol oluşturabilen bir motor da vardır.

Bézier eğrilerini kullanarak nasıl daire oluşturabilirim?


Yakından ilişkili: Geometrik
Yay'dan

Yanıtlar:


141

Daha önce de belirtildiği gibi: Bezier eğrilerini kullanan dairenin kesin bir temsili yoktur.

Diğer cevapları tamamlamak için: nSegmentli Bezier eğrisi için , eğrinin ortasının dairenin kendisi üzerinde olması anlamında, kontrol noktalarına olan en uygun mesafe (4/3)*tan(pi/(2n)).

n segment için formül

Yani 4 puan için (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

4 noktalı durum


2
Optimum mesafeye göre, ne tür ölçümleri optimize ediyorsunuz? Kübik Bézier eğrileri olan bir daireye yaklaşık olarak gösterildiği gibi , mümkün olan en düşük maksimum sapmaya farklı bir değerle ulaşılır. Sizin durumunuzda "optimal" in ne anlama geldiğini veya formülün nasıl türetildiğini tanımlayan bir bağlantı sağlayabilir misiniz?
Suma

1
@Suma bu mesafe için uygun değil. İse uygun bir daire eğrinin orta olması. Ve başka bir kriter koyarsanız kesinlikle daha iyi hale getirilebilir.
Kpym

2
TAMAM. Yeniden ifade etmeye çalışacağım: "kontrol noktalarına olan mesafe, öyle ki eğrinin ortası çemberin üzerinde uzanır." Bunu geçerli bir karar olarak görüyorum (yeterince iyi ve hesaplaması kolay), ancak buna optimal diyemem (en azından hangi anlamda en uygun olduğunu yazmadan).
Suma

1
Evet, çünkü bunun maksimum sapması +% 0,027 ve min. Sapması gerçek çembere göre -0. Sadece gerçek çemberden daha büyüktür, daha iyi bir yaklaşım C'yi% 0,027'nin yarısı kadar hareket ettirerek yapılır. Çemberdeki orta noktaları istiyorsanız, kesinlikle bunu yapmanın yolu budur.
Tatarize

2
@ legends2k Daha sonra PNG'ye dönüştürdüğüm bir PDF oluşturmak için LaTeX'i TikZ ile kullanıyorum.
Kpym

36

Comp.graphics.faq kapsamındadır

Alıntı:

Subject 4.04: Bezier eğrisini daireye nasıl sığdırırım?

İlginçtir ki, Bezier eğrileri bir daireye yaklaşabilir, ancak bir daireye tam olarak uymaz. Yaygın bir yaklaşım, bir çemberi modellemek için dört bezier kullanmaktır; bunların her biri uç noktalardan d = r * 4 * (sqrt (2) -1) / 3 mesafede (burada r daire yarıçapıdır) ve uç noktalarda daireye teğet bir yön. Bu, Beziers'ın orta noktalarının daire üzerinde olmasını ve ilk türevin sürekli olmasını sağlayacaktır.
Bu yaklaşımdaki radyal hata, dairenin yarıçapının yaklaşık% 0,0273'ü olacaktır.

Michael Goldapp, "Kübik polinomlarla dairesel yayların yaklaştırılması" Bilgisayar Destekli Geometrik Tasarım (# 8 1991 s.227-238)

Tor Dokken ve Morten Daehlen, "Eğrilik-sürekli Bezier eğrileriyle dairelerin İyi Yaklaşımları" Bilgisayar Destekli Geometrik Tasarım (# 7 1990 s. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (ücretsiz olmayan makale)

Ayrıca, http://spencermortensen.com/articles/bezier-circle/ adresindeki ödeme duvarlı olmayan makaleye bakın.

Tarayıcılar ve Tuval Öğesi.

Bazı tarayıcıların tuval çizim yayları için Bezier eğrilerini kullandığını, Chrome'un (şu anda) 4 sektörlü bir yaklaşım kullandığını ve Safari'nin 8 sektörlü bir yaklaşım kullandığını, farkın yalnızca yüksek çözünürlükte fark edilebildiğini, çünkü bu% 0,0273 olduğunu unutmayın. yalnızca yaylar paralel olarak ve faz dışı çizildiğinde gerçekten görünür, yayların gerçek bir çemberden salındığını fark edeceksiniz. Eğri, radyal merkezi etrafında hareket ederken etki daha da belirgindir, 600 piksel yarıçapı genellikle bir fark yaratacağı boyuttur.

Bazı çizim API'leri gerçek yay oluşturma özelliğine sahip değildir, bu nedenle Bezier eğrilerini de kullanırlar, örneğin Flash platformunda yay çizim api'si yoktur, bu nedenle yaylar sunan çerçeveler genellikle aynı Bezier eğrisi yaklaşımını kullanır.

Tarayıcılardaki SVG motorlarının farklı bir çizim yöntemi kullanabileceğini unutmayın.

Diğer platformlar

Kullanmaya çalıştığınız platform ne olursa olsun, yay çiziminin nasıl yapıldığını kontrol etmeye değer, böylece bunun gibi görsel hataları tahmin edebilir ve uyarlayabilirsiniz.


Teşekkürler, yerine koyacağım.
ocodo

31

Sorunun cevapları çok iyi, bu yüzden eklenecek çok az şey var. Bundan ilham alarak çözümü görsel olarak doğrulamak için bir deney yapmaya başladım , dört Bézier eğrisinden başlayarak, eğri sayısını bire düşürdüm. Şaşırtıcı bir şekilde, üç Bézier eğrisiyle dairenin benim için yeterince iyi göründüğünü , ancak yapımın biraz zor olduğunu öğrendim . Aslında Inkscape'i siyah 1 piksel genişliğindeki Bézier yaklaşımını kırmızı 3 piksel genişliğindeki bir dairenin üzerine yerleştirmek için kullandım (Inkscape tarafından üretildiği gibi). Açıklama için Bézier eğrilerinin sınırlayıcı kutularını gösteren mavi çizgiler ve yüzeyler ekledim.

Kendinizi görmek için sonuçlarımı sunuyorum:

1 eğri grafiği (tamlık için bir köşede sıkıştırılmış bir damlaya benzeyen):görüntü açıklamasını buraya girin

2 eğri grafiği:görüntü açıklamasını buraya girin

3 eğri grafiği:görüntü açıklamasını buraya girin

4 eğimli grafik: görüntü açıklamasını buraya girin

(SVG'yi veya PDF'yi buraya koymak istedim, ancak bu desteklenmiyor)


1
Şimdiye kadar svg, html kod parçacığı olarak dahil edilebilir. Örneğin bu yanıta bakın: stackoverflow.com/a/32162431
TS

1
@TS: Grafikleri, sahip olduğum SVG'lerle değiştirmeye çalıştığımda, bu yılın başında çalınan bir USB bellekle onları kaybettiğimi fark ettim. Zaman izin verirse, yakında onları yeniden yaratmaya çalışacağım. Ancak, SVG XML kodu olarak eklenebiliyorsa (ve grafik olarak görüntülenmiyorsa) burada pek bir anlam ifade etmiyor.
U. Windl

Tarayıcınız svg'yi destekliyorsa, görüntüler "Kod Parçacığını Çalıştır" ı tıkladığınız anda oluşturulur (görünüşe göre bu düğme stackoverflow'un mobil sürümünde mevcut değildir ...). Bağladığım cevaba bakın.
TS

1
@TS: Daha uzun dosyalar için çok çirkin IMHO.
U. Windl

9

Zaten birçok cevap var ama çok iyi bir kübik bezier yaklaşık bir daireye sahip küçük bir çevrimiçi makale buldum. Birim çember cinsinden c = 0.55191502449, burada c, teğetler boyunca eksen kesişme noktalarından kontrol noktalarına olan mesafedir.

Kontrol noktaları olan iki orta koordinat ile birim çember için tek bir kadran olarak. (0,1),(c,1),(1,c),(1,0)

Radyal hata sadece% 0,019608'dir, bu yüzden onu bu cevaplar listesine eklemek zorunda kaldım.

Makale burada bulunabilir. Kübik Bézier eğrilerine sahip yaklaşık bir daire


5
Stackoverflow'dan Mike 'Pomax' Kamermans'ın Bezier Curves hakkındaki bu mükemmel incelemesini okudunuz mu ? Okumaya değer! :-)
markE

1
@markE Bu bağlantı için çok teşekkür ederim, bu konu hakkında şimdiye kadar gördüğüm "en mükemmel" incelemelerden biri. Ayrıntılı bir şekilde gözden geçirmek için bir şans elde etmek için sabırsızlanıyorum ..: D teşekkürler ...
Blindman67

1
Yani% 0.019608 hatasıyla, yarıçap bir daire içinde 2551 pikselin ötesine geçtiğinde,% 0.027253 (grafik motoru pikseli değiştirecek) korkunç bir yarım pikselden ziyade grafiklerde 4 piksel hatası alacaktır. 1835 pikselde 2 pikselin hatalı olmasına neden oluyor!
Tatarize 01

@Tatarize Makale hatanın nasıl ölçüldüğünü belirtmiyor, maksimum radyal kayma diyor? Hatanın 0 <= t <= 1 eğrisi boyunca en aza indirildiğini varsayıyorum, 0 <= pheta <= Pi / 2'de t = 0 = 1/2 = 1 eşittir pheta = 0 = Pi / 4 = Pi / 4 hata% 0.019608'dir ve t = ~ 0.1822 & t = ~ 0.8177'deki maksimum hata% 0.019608'dir (işaretler?), Ancak bu noktalarda t eşit değildir pheta, hata açısal kaymayı içerir mi? . 4 piksel doğru olabilir de olmayabilir de. Hata varyans olabilir, dolayısıyla r = 2551 için hata <2pix olabilir. İncelenmesi gereken birçok soru
Blindman67

Hata eğrisine baktığımda, verilen ayarlamanın, yay çizgisinin üstündeki maksimum hatanın yay çizgisinin altındaki maksimum hataya eşit olmasına neden olacak kadar basitçe noktayı aşağı doğru hareket ettirdiğinden oldukça eminim. Yani eğriyi biraz aşağı değiştiririz, böylece tüm hata pozitif olmaz. Bu ayarlama, 4 nokta maksimum hata ile yay çizgisini 4 kez geçtiğimiz anlamına gelir. Orijinal olarak belirlenen doğrunun 2 puanı olduğunda, yani t = .25 ve t = .75. Ayarlamalarla t = .125, t = .375 t = .625 t = .875 olmalıdır. Bu, katı pikseller kullandığımızı ve 14px'de değişecek olan kenarları yumuşatılmadığını varsayar.
Tatarize

8

Mümkün değil. Bezier, kübiktir (en azından ... en yaygın kullanılanıdır). Bir daire tam olarak bir kübik ile ifade edilemez, çünkü bir daire, denkleminde bir karekök içerir. Sonuç olarak, yaklaşmalısınız.

Bunu yapmak için, çemberinizi n-tantlara (egquadrantlar, octants) bölmeniz gerekir. Her n-tant için, ilk ve son noktayı Bezier eğrisinin ilk ve sonuncusu olarak kullanırsınız. Bezier poligonu, iki ek nokta gerektirir. Hızlı olmak için, n-tantın her uç noktası için çembere teğet alır ve iki noktayı iki teğetin kesişimi olarak seçerdim (böylece temelde Bezier poligonunuz bir üçgen olur). Hassasiyetinize uyacak şekilde n-tant sayısını artırın.


4
Sıfır uzunlukta sonsuz sayıda bezier eğrisi kullandığınız sürece mümkündür. Bu temelde sonsuz sayıda nokta veya daha doğrusu sadece bir yay eğrisidir.
Tatarize


7

Yalnızca kod arayan kişilere:

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>

Bu, 4 Bezier eğrisinden oluşan daire çizmeye izin verir. JS'de yazılmıştır, ancak başka herhangi bir dile kolayca çevrilebilir

Not

Gerekmedikçe SVG yolunu kullanarak bir daire çizmeniz gerekiyorsa Bezier eğrilerini kullanmayın. ArcYolda 2 yarım daire oluşturmak için kullanabilirsiniz .

SVG'nin yay yolu ile daire çizimi


Bu çok yardımcı oldu, teşekkürler! 4 segmenti sıraya koymak için neyin değiştirilmesi gerekiyor? Bir yol boyunca metin yazmam gerekiyor, ancak şimdi 4 bölüme dağılmış durumda
Alexa

1

Yaklaşımla ilgili olduğu için yeni bir soru açmalı mıyım emin değilim ama Bezier için herhangi bir derecede kontrol noktası elde etmek için genel formülle ilgileniyorum ve bu soruya uyduğuna inanıyorum. Web'de bulduğum tüm çözümler sadece kübik eğriler için ya da ücretli ya da anlamıyorum bile (matematikte pek iyi değilim). Bu yüzden bunu kendi başıma çözmeye karar verdim. Verilen açıya bağlı olarak kontrol noktasının dairenin merkezinden uzaklığını inceliyordum ve şimdiye kadar şunu buldum:

görüntü açıklamasını buraya girin

NTek eğri için kontrol noktalarının sayısı nerede veα açı ark çemberdir.

İkinci dereceden eğri için basitleştirilebilir: l ≈ r + r * PI*0.1 * pow(α/90, 2) Daha PI*0.1ziyade bir tahmin - mükemmel değeri hesaplamadım ama oldukça yakın. Bu, kübik eğri için yaklaşık% 0,2 yarıçap hatası veren 1-2 kontrol noktalı eğri için oldukça iyi çalışır. Daha yüksek dereceli eğriler için doğruluk kaybı fark edilebilir. 3 kontrol noktası ile eğri kuadratiğe benziyor, bu yüzden açıkçası bir şeyi özlüyorum ama çözemiyorum ve bu yöntem genel olarak ihtiyaçlarımı şimdilik karşılıyor. İşte demo .


Bu görüntüyü oluşturmak için hangi yazılımı kullanıyorsunuz?
Qian Sijianhao

1
Win 7 + MS Paint'ten demo + Math yazı
panelimden

0

Bunu ölümden döndürdüğüm için özür dilerim, ancak bu yazıyı genişletilebilir bir formül bulmada bu sayfayla birlikte çok yararlı buldum .

Temel olarak, 4'ün üzerinde herhangi bir sayıda Bezier eğrisini kullanmanıza olanak tanıyan inanılmaz derecede basit bir formül kullanarak yakın bir daire oluşturabilirsiniz: Distance = radius * stepAngle / 3

DistanceBir Bezier kontrol noktası ile yayın en yakın ucu arasındaki mesafe nerede , yarıçap radiusdairenin ve stepAngleyayın 2 ucu arasındaki açıdır ve 2π / (eğri sayısı) ile temsil edilir.

Yani tek seferde vurmak için: Distance = radius * 2π / (the number of curves) / 3


2
Bu, çemberin en iyi yaklaşımı değildir. En iyisi Distance = (4/3)*tan(pi/2n). Çok sayıda yay için neredeyse aynıdır çünkü tan(pi/2)~pi/2nörneğin n=4(en çok kullanılan durum budur) formülünüz verir, Distance=0.5235...ancak en uygun olanıdır Distance=0.5522... (yani ~% 5 hataya sahipsiniz).
Kpym

-2

Çözünürlük ve hassasiyete bağlı olarak makul veya korkunç görünecek ağır bir yaklaşım ama kontrol noktalarım olarak sqrt (2) / 2 x radius kullanıyorum . Bu sayının nasıl elde edildiğini ve okumaya değer olduğunu oldukça uzun bir metin okudum, ancak yukarıdaki formül hızlı ve kirli.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.