Comment créer un cercle avec des courbes de Bézier?


Réponses:


138

Comme déjà dit: il n'y a pas de représentation exacte du cercle en utilisant les courbes de Bézier.

Pour compléter les autres réponses: pour la courbe de Bézier avec nsegments, la distance optimale aux points de contrôle, dans le sens où le milieu de la courbe se trouve sur le cercle lui-même, est (4/3)*tan(pi/(2n)).

formule pour n segments

Donc pour 4 points c'est (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

Cas en 4 points


2
Par distance optimale, quel type de métrique optimisez-vous? Comme indiqué dans Approximer un cercle avec des courbes de Bézier cubiques , la dérive maximale la plus faible possible est obtenue par une valeur différente. Pouvez-vous fournir un lien définissant ce que signifie «optimal» dans votre cas, ou comment la formule est-elle dérivée?
Suma

1
@Suma ce n'est pas optimal pour une certaine distance. Il est optimal d'avoir le milieu de la courbe sur le cercle. Et peut certainement être amélioré si vous mettez un autre critère.
Kpym

2
D'ACCORD. Je vais essayer de reformuler: "la distance aux points de contrôle telle que le milieu de la courbe se trouve sur le cercle lui-même". Je vois cela comme une décision valide (assez bonne et facile à calculer), mais je ne l'appellerais pas optimale (du moins pas sans écrire en quel sens elle est optimale).
Suma

1
Ouais, puisque celui-ci a un écart maximum de + 0,027% et un écart minimum de -0 par rapport au vrai cercle. C'est seulement toujours plus grand que le cercle réel que la meilleure approximation améliorée est faite en déplaçant C de moitié de 0,027%. Si vous voulez les points médians sur le cercle, c'est certainement la manière de le faire.
Tatarize

2
@ legends2k J'utilise LaTeX avec TikZ pour générer un PDF que je convertis ensuite en PNG.
Kpym le

34

Couvert dans le comp.graphics.faq

Extrait:

Sujet 4.04: Comment ajuster une courbe de Bézier à un cercle?

Il est intéressant de noter que les courbes de Bézier peuvent se rapprocher d'un cercle mais pas parfaitement s'adapter à un cercle. Une approximation courante consiste à utiliser quatre beziers pour modéliser un cercle, chacun avec des points de contrôle à une distance d = r * 4 * (sqrt (2) -1) / 3 des points d'extrémité (où r est le rayon du cercle), et en une direction tangente au cercle aux extrémités. Cela garantira que les points médians des Béziers sont sur le cercle et que la première dérivée est continue.
L'erreur radiale dans cette approximation sera d'environ 0,0273% du rayon du cercle.

Michael Goldapp, "Approximation des arcs de cercle par des polynômes cubiques" Conception géométrique assistée par ordinateur (# 8 1991 pp.227-238)

Tor Dokken et Morten Daehlen, «Bonnes approximations de cercles par courbes de Bézier continues à courbure» Conception géométrique assistée par ordinateur (# 7 1990 pp. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (article non gratuit)

Voir également l'article non paywall sur http://spencermortensen.com/articles/bezier-circle/

Navigateurs et élément de canevas.

Notez que certains navigateurs utilisent des courbes de Bézier pour leur arc de dessin de canevas, Chrome utilise (à l'heure actuelle) une approche à 4 secteurs et Safari utilise une approche à 8 secteurs, la différence n'est perceptible qu'en haute résolution, à cause de cela 0,0273%, et aussi Ce n'est vraiment visible que lorsque les arcs sont dessinés en parallèle et déphasés, vous remarquerez que les arcs oscillent à partir d'un vrai cercle. L'effet est également plus perceptible lorsque la courbe s'anime autour de son centre radial, le rayon de 600 px est généralement la taille à laquelle il fera une différence.

Certaines API de dessin n'ont pas de véritable rendu d'arc, elles utilisent donc également des courbes de Bézier, par exemple la plate-forme Flash n'a pas d'API de dessin d'arc, donc tous les frameworks qui offrent des arcs utilisent généralement la même approche de courbe de Bézier.

Notez que les moteurs SVG des navigateurs peuvent utiliser une méthode de dessin différente.

Autres plateformes

Quelle que soit la plate-forme que vous essayez d'utiliser, il vaut la peine de vérifier comment le dessin d'arc est fait, afin que vous puissiez prévoir des erreurs visuelles comme celle-ci et vous adapter.


Merci, je vais le remplacer.
ocodo

31

Les réponses à la question sont très bonnes, il n'y a donc pas grand-chose à ajouter. Inspiré par cela, j'ai commencé à faire une expérience pour confirmer visuellement la solution, en commençant par quatre courbes de Bézier, en réduisant le nombre de courbes à une. Étonnamment, j'ai découvert qu'avec trois courbes de Bézier, le cercle me paraissait assez bien , mais la construction est un peu délicate. En fait, j'ai utilisé Inkscape pour placer l'approximation de Bézier noir de 1 pixel de large sur un cercle rouge de 3 pixels de large (tel que produit par Inkscape). Pour plus de précision, j'ai ajouté des lignes et des surfaces bleues montrant les boîtes englobantes des courbes de Bézier.

Pour vous voir, je vous présente mes résultats:

Le graphique à 1 courbe (qui ressemble à une goutte pressée dans un coin, juste pour être complet):entrez la description de l'image ici

Le graphique à 2 courbes:entrez la description de l'image ici

Le graphique à 3 courbes:entrez la description de l'image ici

Le graphique à 4 courbes: entrez la description de l'image ici

(Je voulais mettre le SVG ou PDF ici, mais ce n'est pas pris en charge)


1
Désormais, svg peut être inclus en tant qu'extrait de code html. Voir par exemple cette réponse: stackoverflow.com/a/32162431
TS

1
@TS: Quand j'ai essayé de remplacer les graphismes par les SVG que j'avais, j'ai réalisé que j'avais perdu ceux avec une clé USB qui avait été volée au début de cette année. Si le temps le permet, j'essaierai de les recréer bientôt. Cependant, si SVG peut être ajouté en tant que code XML (et n'est pas affiché sous forme de graphique), cela n'a pas beaucoup de sens ici.
U. Windl

Si votre navigateur prend en charge svg, alors les images sont rendues dès que vous cliquez sur "Exécuter l'extrait de code" (apparemment ce bouton n'est pas disponible sur la version mobile de stackoverflow ...). Voir dans la réponse que j'ai liée.
TS

1
@TS: Pour les fichiers plus longs, c'est trop moche à mon humble avis.
U. Windl

9

Beaucoup de réponses déjà mais j'ai trouvé un petit article en ligne avec une très bonne approximation cubique de Bézier d'un cercle. En termes de cercle unitaire c = 0,55191502449 où c est la distance des points d'intersection de l'axe le long des tangentes aux points de contrôle.

En tant que quadrant unique pour le cercle unitaire, les deux coordonnées du milieu étant les points de contrôle. (0,1),(c,1),(1,c),(1,0)

L'erreur radiale n'est que de 0,019608%, je devais donc l'ajouter à cette liste de réponses.

L'article peut être trouvé ici Approximation d'un cercle avec des courbes de Bézier cubiques


5
Avez-vous lu cet excellent traité sur les courbes de Bézier par Mike 'Pomax' Kamermans de Stackoverflow . Ça vaut bien la lecture! :-)
markE

1
@markE Merci beaucoup pour ce lien, c'est l'un des "plus excellents" traités que j'ai jamais vu sur le sujet. J'ai hâte d'avoir l'occasion de l'examiner en détail ..: D merci ...
Blindman67

1
Donc, avec une erreur de 0,019608%, les graphiques obtiendront 4 pixels par erreur lorsque le rayon dépasse 2551 pixels dans un cercle plutôt que cet horrible 0,027253% où nous sommes un demi-pixel solide d'erreur (où le moteur graphique changera le pixel) à 1835 px causant une erreur de 2 pixels!
Tatarize

@Tatarize L'article ne précise pas comment l'erreur a été mesurée, il dit dérive radiale maximale? Je suppose que l'erreur est minimisée le long de la courbe 0 <= t <= 1 pour correspondre au quadrant 0 <= pheta <= Pi / 2 à t = 0 = 1/2 = 1 égale pheta = 0 = Pi / 4 = Pi / 4 l'erreur est de 0,019608% et l'erreur maximale à t = ~ 0,1822 & t = ~ 0,8177 de 0,019608% (signes?) Mais à ces points t n'est pas égal à pheta l'erreur inclut-elle la dérive angulaire? . 4 pixels peuvent être corrects ou non. L'erreur peut être une variance, donc une erreur <2pix pour r = 2551. Un grand nombre de questions qui nécessiteront une enquête
Blindman67

Je suis à peu près sûr, après avoir examiné la courbe d'erreur, que l'ajustement donné déplace simplement le point vers le bas de suffisamment pour que l'erreur maximale au-dessus de la ligne d'arc soit égale à l'erreur maximale en dessous de la ligne d'arc. C'est-à-dire que nous modifions un peu la courbe pour que toute erreur ne soit pas positive. Cet ajustement signifie que nous traversons la ligne d'arc 4 fois, avec 4 points d'erreur maximum. Lorsque la ligne spécifiée d'origine avait 2 points, à savoir à t = 0,25 et t = 0,75. Avec les ajustements, il devrait être à t = 0,125, t = 0,375 t = 0,625 t = 0,875. Cela suppose que nous utilisons des pixels solides et non anticrénelés qui changeraient à 14px.
Tatarize

8

Ce n'est pas possible. Un Bézier est un cube (du moins ... le plus couramment utilisé est). Un cercle ne peut pas être exprimé exactement avec un cube, car un cercle contient une racine carrée dans son équation. En conséquence, vous devez approximer.

Pour ce faire, vous devez diviser votre cercle en n-tants (par exemple, quadrants, octants). Pour chaque n-tant, vous utilisez le premier et le dernier point comme premier et dernier de la courbe de Bézier. Le polygone de Bézier nécessite deux points supplémentaires. Pour être rapide, je prendrais les tangentes au cercle pour chaque point extrême du n-tant et choisirais les deux points comme intersection des deux tangentes (de sorte qu'en gros votre polygone de Bézier soit un triangle). Augmentez le nombre de n-tants en fonction de votre précision.


4
C'est possible, tant que vous utilisez un nombre infini de courbes de Bézier, de longueur nulle. Ce qui est fondamentalement un nombre infini de points, ou plutôt juste une courbe en arc.
Tatarize


7

Aux personnes qui recherchent simplement du code:

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>

Cela permet de dessiner un cercle composé de 4 courbes de Bézier. Écrit en JS mais peut facilement être traduit dans n'importe quelle autre langue


C'est très utile, merci! Que faut-il changer pour mettre les 4 segments dans l'ordre? J'ai besoin d'écrire du texte le long d'un chemin, mais maintenant il est dispersé autour des 4 segments
Alexa

1

Je ne sais pas si je devrais ouvrir une nouvelle question car il s'agit d'aproximation, mais je suis intéressé par la formule générale pour obtenir des points de contrôle pour Bézier de n'importe quel degré et je pense que cela s'inscrit dans cette question. Toutes les solutions que j'ai trouvées sur le web sont uniquement pour les courbes cubiques ou sont payantes ou je ne comprends même pas (je ne suis pas très bon en maths). J'ai donc décidé d'essayer de résoudre ce problème par moi-même. J'étudiais la distance du point de contrôle à partir du centre d'un cercle en fonction de l'angle donné et jusqu'à présent, j'ai trouvé que:

entrez la description de l'image ici

Nest le nombre de points de contrôle pour une seule courbe et l' αangle de l'arc de cercle.

Pour la courbe quadratique, cela peut être simplifié en l ≈ r + r * PI*0.1 * pow(α/90, 2) Le PI*0.1est plutôt une supposition - je n'ai pas calculé la valeur parfaite mais c'est assez proche. Cela fonctionne raisonnablement bien pour une courbe avec 1-2 points de contrôle donnant une erreur de rayon d'environ 0,2% pour la courbe cubique. Pour les courbes de degré supérieur, une perte de précision est perceptible. Avec 3 points de contrôle, la courbe ressemble à la courbe quadratique, donc je manque évidemment quelque chose, mais je ne peux pas le comprendre et cette méthode répond généralement à mes besoins pour le moment. Voici la démo .


Quel logiciel utilisez-vous pour créer cette image?
Qian Sijianhao

1
Capture d'écran de ma démo + panneau d'écriture mathématique (ou comment le nom est traduit) de win 7 + MS Paint
Paweł Audionysos

0

Désolé de ramener celui-ci d'entre les morts, mais j'ai trouvé ce post très utile avec cette page pour proposer une formule extensible.

Fondamentalement, vous pouvez créer un cercle proche en utilisant une formule incroyablement simple qui vous permet d'utiliser n'importe quel nombre de courbes de Bézier sur 4: Distance = radius * stepAngle / 3

Distanceest la distance entre un point de contrôle de Bézier et l'extrémité la plus proche de l'arc, le rayon est le radiusdu cercle et stepAngleest l'angle entre les 2 extrémités de l'arc comme représenté par 2π / (le nombre de courbes).

Donc, pour le frapper d'un seul coup: Distance = radius * 2π / (the number of curves) / 3


1
Ce n'est pas la meilleure approximation d'un cercle. Le meilleur est Distance = (4/3)*tan(pi/2n). Pour un grand nombre d'arcs, c'est presque la même chose car tan(pi/2)~pi/2n, mais par exemple pour n=4(ce qui est le cas le plus utilisé), votre formule donne Distance=0.5235...mais la formule optimale est Distance=0.5522... (donc vous avez ~ 5% d'erreur).
Kpym

-2

C'est une approximation lourde qui paraîtra raisonnable ou terrible selon la résolution et la précision, mais j'utilise sqrt (2) / 2 x radius comme points de contrôle. J'ai lu un texte assez long sur la façon dont ce nombre est dérivé et cela vaut la peine d'être lu, mais la formule ci-dessus est rapide et sale.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.