Wie erstelle ich einen Kreis mit Bézier-Kurven?


Antworten:


138

Wie bereits gesagt: Es gibt keine exakte Darstellung des Kreises mit Bezier-Kurven.

Um die anderen Antworten zu vervollständigen: Für die Bezier-Kurve mit nSegmenten ist der optimale Abstand zu den Kontrollpunkten in dem Sinne, dass die Mitte der Kurve auf dem Kreis selbst liegt (4/3)*tan(pi/(2n)).

Formel für n Segmente

Also für 4 Punkte ist es (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.552284749831.

4-Punkte-Fall


2
Welche Metriken optimieren Sie bei optimaler Entfernung? Wie in Näherungskreis mit kubischen Bézier-Kurven gezeigt , wird die niedrigstmögliche maximale Drift durch einen anderen Wert erreicht. Können Sie einen Link angeben, der definiert, was "optimal" in Ihrem Fall bedeutet oder wie die Formel abgeleitet wird?
Suma

1
@Suma das ist für einige Entfernungen nicht optimal. Es ist optimal , die Mitte der Kurve auf dem Kreis zu haben. Und sicherlich kann es besser gemacht werden, wenn Sie ein anderes Kriterium setzen.
Kpym

2
OK. Ich werde versuchen, Folgendes umzuformulieren: "Der Abstand zu den Kontrollpunkten so, dass die Mitte der Kurve auf dem Kreis selbst liegt." Ich sehe dies als eine gültige Entscheidung (gut genug und leicht zu berechnen), aber ich würde es nicht als optimal bezeichnen (zumindest nicht ohne zu schreiben, in welchem ​​Sinne es optimal ist).
Suma

1
Ja, da dieser eine maximale Abweichung von + 0,027% und eine minimale Abweichung von -0 gegenüber dem wahren Kreis hat. Es ist immer nur größer als der reale Kreis. Die besser verbesserte Annäherung wird erreicht, indem C um die Hälfte von 0,027% verschoben wird. Wenn Sie jedoch die Mittelpunkte auf dem Kreis haben möchten, ist dies sicherlich der richtige Weg.
Tatarize

2
@ legends2k Ich verwende LaTeX mit TikZ, um ein PDF zu generieren, das ich dann in PNG konvertiere.
Kpym

34

In der comp.graphics.faq

Auszug:

Thema 4.04: Wie passe ich eine Bezier-Kurve an einen Kreis an?

Interessanterweise können Bezier-Kurven einen Kreis approximieren, passen aber nicht perfekt zu einem Kreis. Eine übliche Annäherung besteht darin, vier Bezier zum Modellieren eines Kreises zu verwenden, wobei jeder Kontrollpunkt einen Abstand d = r * 4 * (sqrt (2) -1) / 3 von den Endpunkten (wobei r der Kreisradius ist) und in eine Richtung, die den Kreis an den Endpunkten tangiert. Dadurch wird sichergestellt, dass sich die Mittelpunkte der Beziers auf dem Kreis befinden und dass die erste Ableitung stetig ist.
Der radiale Fehler in dieser Näherung beträgt ungefähr 0,0273% des Radius des Kreises.

Michael Goldapp, "Approximation von Kreisbögen durch kubische Polynome" Computer Aided Geometric Design (# 8 1991, S. 227-238)

Tor Dokken und Morten Daehlen, "Gute Annäherungen von Kreisen durch krümmungskontinuierliche Bezier-Kurven" Computer Aided Geometric Design (# 7 1990, S. 33-41). http://www.sciencedirect.com/science/article/pii/016783969090019N (nicht kostenloser Artikel)

Siehe auch den Artikel ohne Paywall unter http://spencermortensen.com/articles/bezier-circle/

Browser und Canvas-Element.

Beachten Sie, dass einige Browser Bezier-Kurven für ihren Zeichenbogen verwenden, Chrome (derzeit) einen 4-Sektor-Ansatz und Safari einen 8-Sektor-Ansatz verwendet. Der Unterschied ist aufgrund dieser 0,0273% nur bei hoher Auflösung spürbar Nur wenn Bögen parallel und phasenverschoben gezeichnet werden, werden Sie feststellen, dass die Bögen von einem echten Kreis aus schwingen. Der Effekt macht sich auch deutlicher bemerkbar, wenn die Kurve um ihren radialen Mittelpunkt animiert wird. Der Radius von 600 Pixel ist normalerweise die Größe, in der er einen Unterschied macht.

Bestimmte Zeichnungs-APIs verfügen nicht über ein echtes Arc-Rendering, daher verwenden sie auch Bezier-Kurven. Beispielsweise verfügt die Flash-Plattform über keine API zum Zeichnen von Bögen. Daher verwenden Frameworks, die Bögen anbieten, im Allgemeinen denselben Bezier-Kurvenansatz.

Beachten Sie, dass SVG-Engines in Browsern möglicherweise eine andere Zeichenmethode verwenden.

Andere Plattformen

Unabhängig davon, welche Plattform Sie verwenden möchten, sollten Sie überprüfen, wie das Zeichnen von Bögen durchgeführt wird, damit Sie solche visuellen Fehler vorhersagen und anpassen können.


Danke, ich werde es ersetzen.
ocodo

31

Die Antworten auf die Frage sind sehr gut, daher gibt es wenig hinzuzufügen. Inspiriert davon begann ich ein Experiment zur visuellen Bestätigung der Lösung, beginnend mit vier Bézier-Kurven, wobei die Anzahl der Kurven auf eins reduziert wurde. Erstaunlicherweise fand ich heraus, dass der Kreis mit drei Bézier-Kurven gut genug für mich aussah , aber die Konstruktion ist etwas schwierig. Eigentlich habe ich Inkscape verwendet, um die schwarze 1 Pixel breite Bézier-Näherung über einem roten 3 Pixel breiten Kreis zu platzieren (wie von Inkscape erzeugt). Zur Verdeutlichung habe ich blaue Linien und Flächen hinzugefügt, die die Begrenzungsrahmen der Bézier-Kurven zeigen.

Um sich selbst zu sehen, präsentiere ich meine Ergebnisse:

Das 1-Kurven-Diagramm (das der Vollständigkeit halber wie ein Tropfen aussieht, der in eine Ecke gedrückt wird):Geben Sie hier die Bildbeschreibung ein

Das 2-Kurven-Diagramm:Geben Sie hier die Bildbeschreibung ein

Das 3-Kurven-Diagramm:Geben Sie hier die Bildbeschreibung ein

Das 4-Kurven-Diagramm: Geben Sie hier die Bildbeschreibung ein

(Ich wollte die SVG oder PDF hier einfügen, aber das wird nicht unterstützt)


1
Inzwischen kann svg als HTML-Code-Snippet eingefügt werden. Siehe zum Beispiel diese Antwort: stackoverflow.com/a/32162431
TS

1
@TS: Als ich versuchte, die Grafiken durch die SVGs zu ersetzen, die ich hatte, stellte ich fest, dass ich diese mit einem USB-Stick verloren hatte, der Anfang dieses Jahres gestohlen worden war. Wenn es die Zeit erlaubt, werde ich versuchen, sie bald neu zu erstellen. Wenn SVG jedoch als XML-Code hinzugefügt werden kann (und nicht als Grafik angezeigt wird), ist dies hier nicht sehr sinnvoll.
U. Windl

Wenn Ihr Browser svg unterstützt, werden die Bilder gerendert, sobald Sie auf "Run Code Snippet" klicken (anscheinend ist diese Schaltfläche in der mobilen Version von stackoverflow nicht verfügbar ...). Siehe in der Antwort, die ich verlinkt habe.
TS

1
@TS: Für längere Dateien ist es meiner Meinung nach zu hässlich.
U. Windl

9

Viele Antworten bereits, aber ich fand einen kleinen Online-Artikel mit einer sehr guten kubischen Bezier-Näherung eines Kreises. In Bezug auf den Einheitskreis ist c = 0,55191502449, wobei c der Abstand von den Achsenschnittpunkten entlang der Tangenten zu den Kontrollpunkten ist.

Als einzelner Quadrant für den Einheitskreis, wobei die beiden mittleren Koordinaten die Kontrollpunkte sind. (0,1),(c,1),(1,c),(1,0)

Der radiale Fehler beträgt nur 0,019608%, daher musste ich ihn nur zu dieser Liste von Antworten hinzufügen.

Den Artikel finden Sie hier. Näherungsweise eines Kreises mit kubischen Bézier-Kurven


5
Haben Sie diese Zeilen lesen hervorragende Abhandlung über Bezier - Kurven von Stackoverflow des Mike ‚Pomax‘ Kamermans . Es lohnt sich zu lesen! :-)
markE

1
@markE Vielen Dank für diesen Link, der eine der "hervorragendsten" Abhandlungen ist, die ich jemals zu diesem Thema gesehen habe. Ich kann es kaum erwarten, eine Gelegenheit zu bekommen, es im Detail durchzugehen ..: D danke ...
Blindman67

1
Bei einem Fehler von 0,019608% erhalten die Grafiken 4 Pixel Fehler, wenn der Radius 2551 Pixel in einem Kreis überschreitet, anstatt dieser schrecklichen 0,027253%, bei denen es sich um ein solides halbes Fehlerpixel handelt (bei dem die Grafik-Engine das Pixel ändert). bei 1835 px verursachen 2 Pixel einen Fehler!
Tatarize

@Tatarize Der Artikel gibt nicht an, wie der Fehler gemessen wurde, er sagt maximale radiale Drift? Ich nehme an, dass der Fehler entlang der Kurve 0 <= t <= 1 minimiert wird, um mit dem Quadranten 0 <= Pheta <= Pi / 2 bei t = 0 = 1/2 = 1 gleich Pheta = 0 = Pi / 4 = Pi / übereinzustimmen 4 Der Fehler beträgt 0,019608% und der maximale Fehler bei t = ~ 0,1822 & t = ~ 0,8177 von 0,019608% (Vorzeichen?), Aber an diesen Punkten ist t nicht gleich Pheta. Enthält der Fehler die Winkeldrift? . 4 Pixel können korrekt sein oder auch nicht. Der Fehler kann Varianz sein, also Fehler <2pix für r = 2551. Viele Fragen, die untersucht werden müssen
Blindman67

Ich bin mir ziemlich sicher, nachdem ich mir die Fehlerkurve angesehen habe, dass die angegebene Einstellung den Punkt einfach so weit nach unten verschiebt, dass der maximale Fehler über der Bogenlinie dem maximalen Fehler unter der Bogenlinie entspricht. Das heißt, wir ändern die Kurve etwas nach unten, damit der Fehler nicht positiv ist. Diese Anpassung bedeutet, dass wir die Bogenlinie viermal mit 4 Punkten maximalen Fehlers überqueren. Wenn die ursprünglich angegebene Linie 2 Punkte hatte, nämlich bei t = 0,25 und t = 0,75. Bei den Einstellungen sollte es bei t = .125, t = .375 t = .625 t = .875 sein. Dies setzt voraus, dass wir feste Pixel verwenden und kein Anti-Aliasing, das sich bei 14px ändern würde.
Tatarize

8

Es ist nicht möglich. Ein Bezier ist ein Kubikmeter (zumindest ... wird am häufigsten verwendet). Ein Kreis kann nicht genau mit einer Kubik ausgedrückt werden, da ein Kreis eine Quadratwurzel in seiner Gleichung enthält. Infolgedessen müssen Sie annähern.

Dazu müssen Sie Ihren Kreis in n-Tanten (zB Quadranten, Oktanten) teilen. Für jeden n-Tant verwenden Sie den ersten und letzten Punkt als ersten und letzten Punkt der Bezier-Kurve. Das Bezier-Polygon benötigt zwei zusätzliche Punkte. Um schnell zu sein, würde ich die Tangenten für jeden Extrempunkt des n-Tants zum Kreis bringen und die beiden Punkte als Schnittpunkt der beiden Tangenten auswählen (so dass Ihr Bezier-Polygon im Grunde genommen ein Dreieck ist). Erhöhen Sie die Anzahl der n-Tants entsprechend Ihrer Präzision.


4
Es ist möglich, solange Sie eine unendliche Anzahl von Bezierkurven mit einer Länge von Null verwenden. Das ist im Grunde eine unendliche Anzahl von Punkten oder eher nur eine Bogenkurve.
Tatarize


6

Für Leute, die nur nach Code suchen:

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>

Dies ermöglicht das Zeichnen eines Kreises, der aus 4 Bezier-Kurven besteht. Geschrieben in JS, kann aber leicht in jede andere Sprache übersetzt werden


1

Ich bin mir nicht sicher, ob ich eine neue Frage eröffnen soll, da es sich um eine Annäherung handelt, aber ich bin an einer allgemeinen Formel interessiert, um Kontrollpunkte für Bezier jeglichen Grades zu erhalten, und ich glaube, dass sie in diese Frage passt. Alle Lösungen, die ich im Web gefunden habe, sind nur für kubische Kurven oder werden bezahlt oder ich verstehe nicht einmal (ich bin nicht sehr gut in Mathe). Also habe ich beschlossen, dies selbst zu lösen. Ich habe die Entfernung des Kontrollpunkts vom Mittelpunkt eines Kreises in Abhängigkeit vom gegebenen Winkel untersucht und bisher festgestellt, dass:

Geben Sie hier die Bildbeschreibung ein

Wo Nist die Anzahl der Kontrollpunkte für eine einzelne Kurve und αist der Kreisbogenwinkel.

Für eine quadratische Kurve kann sie vereinfacht werden. l ≈ r + r * PI*0.1 * pow(α/90, 2) Das PI*0.1ist eher eine Vermutung - ich habe keinen perfekten Wert berechnet, aber es ist ziemlich nah. Dies funktioniert ziemlich gut für Kurven mit 1-2 Kontrollpunkten, was einen Radiusfehler von etwa 0,2% für kubische Kurven ergibt. Bei Kurven höheren Grades ist ein Genauigkeitsverlust erkennbar. Mit 3 Kontrollpunkten sieht die Kurve ähnlich wie quadratisch aus, daher vermisse ich offensichtlich etwas, aber ich kann es nicht herausfinden, und diese Methode entspricht im Allgemeinen meinen aktuellen Anforderungen. Hier ist eine Demo .


Mit welcher Software erstellen Sie dieses Bild??
Qian Sijianhao

1
Screenshot von meiner Demo + Math Writing Panel (oder wie auch immer der Name übersetzt wird) von Win 7 + MS Paint
Paweł Audionysos

0

Es tut mir leid, diesen Beitrag von den Toten zurückzubringen, aber ich fand diesen Beitrag zusammen mit dieser Seite sehr hilfreich , um eine erweiterbare Formel zu entwickeln.

Grundsätzlich können Sie einen Nahkreis mit einer unglaublich einfachen Formel erstellen, mit der Sie eine beliebige Anzahl von Bezier-Kurven über 4 verwenden können: Distance = radius * stepAngle / 3

Wo Distanceist der Abstand zwischen einem Bezier-Kontrollpunkt und dem nächsten Ende des Bogens, der Radius ist der radiusdes Kreises und stepAngleist der Winkel zwischen den beiden Enden des Bogens, dargestellt durch 2π / (die Anzahl der Kurven).

Um es auf einen Schlag zu treffen: Distance = radius * 2π / (the number of curves) / 3


1
Dies ist nicht die beste Annäherung an einen Kreis. Das beste ist Distance = (4/3)*tan(pi/2n). Für eine große Anzahl von Bögen ist es fast dasselbe, weil tan(pi/2)~pi/2n, aber zum Beispiel für n=4(was der am häufigsten verwendete Fall ist) Ihre Formel gibt, Distance=0.5235...aber die optimale ist Distance=0.5522... (also haben Sie ~ 5% Fehler).
Kpym

-2

Es ist eine schwere Annäherung, die je nach Auflösung und Präzision vernünftig oder schrecklich aussieht, aber ich verwende den Radius sqrt (2) / 2 x als Kontrollpunkte. Ich habe einen ziemlich langen Text gelesen, wie diese Zahl abgeleitet wird, und es lohnt sich zu lesen, aber die obige Formel ist schnell und schmutzig.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.