Come creare un cerchio con le curve di Bézier?


Risposte:


139

Come già detto: non esiste una rappresentazione esatta del cerchio utilizzando le curve di Bézier.

Per completare le altre risposte: per curva di Bézier con nsegmenti la distanza ottimale dai punti di controllo, nel senso che il centro della curva giace sul cerchio stesso, è (4/3)*tan(pi/(2n)).

formula per n segmenti

Quindi per 4 punti lo è (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

Caso a 4 punti


2
In base alla distanza ottimale, che tipo di metriche stai ottimizzando? Come mostrato in Approssimare un cerchio con curve di Bézier cubiche , la deriva massima più bassa possibile si ottiene con un valore diverso. Potete fornire qualche collegamento che definisca cosa significa "ottimale" nel vostro caso, o come è derivata la formula?
Suma

1
@Suma questo non è ottimale per una certa distanza. È ottimale avere il centro della curva sul cerchio. E certamente può essere migliorato se metti un altro criterio.
Kpym

2
OK. Proverò a riformulare: "la distanza dai punti di controllo tale che il centro della curva si trovi sul cerchio stesso". La vedo come una decisione valida (abbastanza buona e facile da calcolare), ma non la definirei ottimale (almeno non senza scrivere in che senso è ottimale).
Suma

1
Sì, poiché questo ha una deviazione massima di + 0,027% e una deviazione minima di -0 rispetto al cerchio vero. È sempre più grande del cerchio reale, l'approssimazione migliore è ottenuta spostando C della metà dello 0,027%. Se vuoi i punti medi del cerchio, questo è sicuramente il modo per farlo.
Tatarize

2
@ legends2k Uso LaTeX con TikZ per generare un PDF che poi converto in PNG.
Kpym

35

Coperto in comp.graphics.faq

Estratto:

Soggetto 4.04: come adattare una curva di Bézier a un cerchio?

È interessante notare che le curve di Bézier possono approssimare un cerchio ma non adattarsi perfettamente a un cerchio. Un'approssimazione comune consiste nell'usare quattro bezier per modellare un cerchio, ciascuno con punti di controllo a distanza d = r * 4 * (sqrt (2) -1) / 3 dai punti finali (dove r è il raggio del cerchio), e in una direzione tangente al cerchio nei punti finali. Ciò garantirà che i punti medi di Beziers siano sul cerchio e che la prima derivata sia continua.
L'errore radiale in questa approssimazione sarà circa lo 0,0273% del raggio del cerchio.

Michael Goldapp, "Approssimazione di archi circolari mediante polinomi cubici" Computer Aided Geometric Design (# 8 1991 pp.227-238)

Tor Dokken e Morten Daehlen, "Buone approssimazioni di cerchi mediante curve di Bezier continue con curvatura" Computer Aided Geometric Design (# 7 1990 pp. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (articolo non gratuito)

Vedi anche l'articolo non protetto da paywall su http://spencermortensen.com/articles/bezier-circle/

Browser ed elemento Canvas.

Nota che alcuni browser utilizzano le curve di Bézier per disegnare l'arco della tela, Chrome utilizza (al momento) un approccio a 4 settori e Safari utilizza un approccio a 8 settori, la differenza è evidente solo ad alta risoluzione, a causa di quello 0,0273%, e anche Veramente visibile solo quando gli archi sono disegnati in parallelo e fuori fase, noterai che gli archi oscillano da un vero cerchio. L'effetto è anche più evidente quando la curva si anima intorno al suo centro radiale, il raggio di 600 px è solitamente la dimensione in cui farà la differenza.

Alcune API di disegno non hanno un rendering ad arco reale, quindi usano anche curve di Bézier, ad esempio la piattaforma Flash non ha API di disegno ad arco, quindi qualsiasi framework che offre archi utilizza generalmente lo stesso approccio della curva di Bézier.

Tieni presente che i motori SVG nei browser potrebbero utilizzare un metodo di disegno diverso.

Altre piattaforme

Qualunque sia la piattaforma che stai cercando di utilizzare, vale la pena controllare per vedere come viene eseguito il disegno dell'arco, in modo da poter prevedere errori visivi come questo e adattarti.


Grazie, lo sostituisco.
ottobre

31

Le risposte alla domanda sono molto buone, quindi c'è poco da aggiungere. Ispirato da ciò ho iniziato a fare un esperimento per confermare visivamente la soluzione, iniziando con quattro curve di Bézier, riducendo il numero di curve a una. Sorprendentemente ho scoperto che con tre curve di Bézier il cerchio mi sembrava abbastanza buono , ma la costruzione è un po 'complicata. In realtà ho usato Inkscape per posizionare l'approssimazione di Bézier nera di 1 pixel su un cerchio rosso di 3 pixel (come prodotto da Inkscape). Per chiarimenti ho aggiunto linee e superfici blu che mostrano i riquadri di delimitazione delle curve di Bézier.

Per vedere te stesso, presento i miei risultati:

Il grafico a 1 curva (che sembra una goccia schiacciata in un angolo, solo per completezza):inserisci qui la descrizione dell'immagine

Il grafico a 2 curve:inserisci qui la descrizione dell'immagine

Il grafico a 3 curve:inserisci qui la descrizione dell'immagine

Il grafico a 4 curve: inserisci qui la descrizione dell'immagine

(Volevo mettere l'SVG o il PDF qui, ma non è supportato)


1
A questo punto, svg può essere incluso come snippet di codice html. Vedi ad esempio questa risposta: stackoverflow.com/a/32162431
TS

1
@TS: Quando ho provato a sostituire la grafica con gli SVG che avevo, mi sono reso conto di aver perso quelli con una chiavetta USB che era stata rubata all'inizio di quest'anno. Se il tempo lo permette, cercherò di ricrearli presto. Tuttavia, se SVG può essere aggiunto come codice XML (e non viene visualizzato come grafica) non ha molto senso qui.
U. Windl

Se il tuo browser supporta svg, le immagini vengono renderizzate non appena fai clic su "Esegui frammento di codice" (apparentemente quel pulsante non è disponibile sulla versione mobile di stackoverflow ...). Vedi nella risposta che ho collegato.
TS

1
@TS: Per file più lunghi è troppo brutto IMHO.
U. Windl

9

Molte risposte già, ma ho trovato un piccolo articolo online con un'ottima approssimazione cubica di un cerchio. In termini di cerchio unitario c = 0,55191502449 dove c è la distanza dai punti di intercettazione dell'asse lungo le tangenti ai punti di controllo.

Come un singolo quadrante per il cerchio unitario con le due coordinate centrali che sono i punti di controllo. (0,1),(c,1),(1,c),(1,0)

L'errore radiale è solo dello 0,019608%, quindi ho dovuto aggiungerlo a questo elenco di risposte.

L'articolo può essere trovato qui Approssimare un cerchio con curve di Bézier cubiche


5
Hai letto questo eccellente trattato sulle curve di Bezier di Mike "Pomax" Kamermans di Stackoverflow . Vale la pena leggerlo! :-)
markE

1
@markE Grazie mille per quel collegamento, che è uno dei trattati "più eccellenti" che abbia mai visto sull'argomento. Non vedo l'ora di avere la possibilità di esaminarlo in dettaglio ..: D grazie ...
Blindman67

1
Quindi con un errore dello 0,019608% la grafica otterrà 4 pixel per errore quando il raggio supera i 2551 pixel in un cerchio piuttosto che quell'orribile 0,027253% in cui siamo un solido mezzo pixel di errore (dove il motore grafico cambierà il pixel) a 1835 px causando un errore di 2 pixel!
Tatarize

@Tatarize L'articolo non specifica come è stato misurato l'errore, dice la massima deriva radiale? Presumo che l'errore sia minimizzato lungo la curva 0 <= t <= 1 per abbinare il quadrante 0 <= pheta <= Pi / 2 at = 0 = 1/2 = 1 è uguale a pheta = 0 = Pi / 4 = Pi / 4 l'errore è 0,019608% e l'errore massimo at = ~ 0,1822 & t = ~ 0,8177 di 0,019608% (segni?) Ma in questi punti t non è uguale a pheta l'errore include la deriva angolare? . 4 pixel possono essere corretti o meno. L'errore può essere la varianza, quindi errore <2pix per r = 2551. Molte domande che richiederanno indagini
Blindman67

Sono abbastanza sicuro, dopo aver esaminato la curva di errore, che la regolazione data sposta semplicemente il punto verso il basso abbastanza da far sì che l'errore massimo sopra la linea dell'arco sia uguale all'errore massimo sotto la linea dell'arco. Vale a dire che cambiamo leggermente la curva in modo che l'errore non sia positivo. Questa regolazione significa che stiamo attraversando la linea dell'arco 4 volte, con 4 punti di errore massimo. Quando la linea specificata originariamente aveva 2 punti, vale a dire at = 0,25 e t = 0,75. Con le regolazioni dovrebbe essere at = .125, t = .375 t = .625 t = .875. Questo presuppone che stiamo usando pixel solidi e non anti-alias che cambierebbero a 14px.
Tatarize

8

Non è possibile. Un Bézier è un cubo (almeno ... il più comunemente usato è). Un cerchio non può essere espresso esattamente con un cubo, perché un cerchio contiene una radice quadrata nella sua equazione. Di conseguenza, devi approssimare.

Per fare questo, devi dividere il tuo cerchio in n-tants (egquadrants, ottants). Per ogni n-tant, usi il primo e l'ultimo punto come primo e ultimo della curva di Bézier. Il poligono di Bézier richiede due punti aggiuntivi. Per essere veloce, prenderei le tangenti al cerchio per ogni punto estremo dell'n-tant e sceglierei i due punti come intersezione delle due tangenti (in modo che fondamentalmente il tuo poligono di Bezier sia un triangolo). Aumenta il numero di n-tants in base alla tua precisione.


4
È possibile, a patto di utilizzare un numero infinito di curve di Bézier, di lunghezza zero. Che è fondamentalmente un numero infinito di punti, o meglio solo una curva ad arco.
Tatarize


7

Per le persone che stanno solo cercando il codice:

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>

Ciò consente di disegnare un cerchio composto da 4 curve di Bézier. Scritto in JS ma facilmente traducibile in qualsiasi altra lingua

Nota

Non utilizzare le curve di Bézier se è necessario disegnare un cerchio utilizzando il percorso SVG a meno che non sia necessario. Nel percorso è possibile utilizzare Arcper creare 2 semicerchi.

Disegno del cerchio con il percorso dell'arco di SVG


Questo è molto utile, grazie! Cosa occorre cambiare per mettere in ordine i 4 segmenti? Devo scrivere del testo lungo un percorso, ma ora è sparso nei 4 segmenti
Alexa

1

Non sono sicuro di dover aprire una nuova domanda poiché si tratta di approssimazione, ma sono interessato alla formula generale per ottenere punti di controllo per Bezier di qualsiasi grado e credo che rientri in questa domanda. Tutte le soluzioni che ho trovato sul web sono solo per curve cubiche o sono a pagamento o non capisco nemmeno (non sono molto bravo in matematica). Quindi ho deciso di provare a risolverlo da solo. Stavo studiando la distanza del punto di controllo dal centro di un cerchio dipendente da un dato angolo e finora ho scoperto che:

inserisci qui la descrizione dell'immagine

Dove Nè il numero di punti di controllo per curva singola ed αè l'angolo dell'arco di cerchio.

Per la curva quadratica può essere semplificato in l ≈ r + r * PI*0.1 * pow(α/90, 2) Il PI*0.1è piuttosto un'ipotesi: non ho calcolato il valore perfetto ma è abbastanza vicino. Questo funziona ragionevolmente bene per la curva con 1-2 punti di controllo che danno un errore di raggio di circa lo 0,2% per la curva cubica. Per curve di grado superiore si nota una perdita di precisione. Con 3 punti di controllo la curva sembra simile a quella quadratica, quindi ovviamente mi manca qualcosa ma non riesco a capirlo e questo metodo generalmente si adatta alle mie esigenze per ora. Ecco la demo .


Quale software usi per creare questa immagine?
Qian Sijianhao

1
Screenshot dalla mia demo + pannello di scrittura matematica (o comunque il nome è tradotto) da win 7 + MS Paint
Paweł Audionysos

0

Mi dispiace riportarlo dalla morte, ma ho trovato questo post molto utile insieme a questo pagina nel fornire una formula espandibile.

Fondamentalmente, puoi creare un cerchio vicino usando una formula incredibilmente semplice che ti consente di utilizzare un numero qualsiasi di curve di Bézier su 4: Distance = radius * stepAngle / 3

Dov'è Distancela distanza tra un punto di controllo di Bézier e l'estremità più vicina dell'arco, il raggio è quello radiusdel cerchio estepAngle è l'angolo tra le 2 estremità dell'arco rappresentato da 2π / (il numero di curve).

Quindi, per colpirlo in un colpo solo: Distance = radius * 2π / (the number of curves) / 3


1
Questa non è la migliore approssimazione di un cerchio. Il migliore è Distance = (4/3)*tan(pi/2n). Per un numero elevato di archi è quasi lo stesso perché tan(pi/2)~pi/2n, ma ad esempio per n=4(che è il caso più utilizzato) la tua formula fornisce Distance=0.5235...ma quella ottimale è Distance=0.5522... (quindi hai un errore di ~ 5%).
Kpym

-2

È un'approssimazione pesante che sembrerà ragionevole o terribile a seconda della risoluzione e della precisione, ma uso sqrt (2) / 2 x raggio come punti di controllo. Ho letto un testo piuttosto lungo su come viene derivato quel numero e vale la pena leggerlo, ma la formula sopra è veloce e sporca.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.