Hallo Habe so ein tolles Dipslay von Display 3000 mit Atmel 128 und möchte einen Kreis darstellen oder Kurven. Ich habe einen Befehl der einzelne Pixel setzt an Xund Y Pos. Wie kann man die einzelen pixel für einen Kreis berechnen??? Vielen Dank
Wenn Du einen Pixel setzen kannst, und Du in der Schule (6 Klasse ?) aufgepasst hast, dann solltest Du auch einen Kreis ausgeben können!
Bresenham lernt man nicht in der Schule, sondern im Internet Aber die Berechnungen sind einfache Additionen und Schiebeoperationen, das ist wirklich nicht schwer, Herr Lehrer
Ich habe bei Bresenham immer ein Verständnisproblem: Wie kann ich Kreissegmente (effizient) realisieren, die nicht aus den Achtelkreisen bestehen (z.B. Kreisbogen von "2 Uhr" nach "1 Uhr")?
Das habe ich auch tunlichst vermieden, meine Routine zeichnet nur ganze Achtel.
> Ich habe bei Bresenham immer ein Verständnisproblem: Wie kann ich > Kreissegmente (effizient) realisieren, die nicht aus den > Achtelkreisen bestehen (z.B. Kreisbogen von "2 Uhr" nach "1 Uhr")? Das würde mich auch interessieren. Weiss jemand, ob es dazu so etwas "einfaches" wie den Bresenham gibt? Und wenn wir schon dabei sind, was ist mit Ellipsen, usw.? Ralf
Ich will nicht unbedingt etwas Zeichnen, sondern etwas fräsen... Hab mich aber noch nicht weiter mit entsprechenden CNC-Seiten auseinandergesetzt. Eigentlich müsste man für den entsprechenden Radius die Punkte in ein Feld schreiben (was natürlich recht groß werden kann), dann die dem Kreissegment entsprecheden Punkte aus den Teilkreisen "zusammenbasteln". Das Feld würde natürlich mit dem Radius wachsen.
@Christoph Kessler In der ursprünglichen Frage war nicht die Rede von einer schnellen Routine, sondern generell, wie zeichne ich einen Kreis, wenn ich eine Funktion zum Setzen von Pixeln habe. Wenn einer schon mal was von Kreisradius, Sinus und Cosinus (6 Klasse?) gehört hat, dann sollte er wissen wie es geht - auch für CNC oder Plotter Anwendungen...
Die Fräsplotter arbeiten, soweit ich weiß, immer noch mit dem guten alten HPGL, da gibts einen Kreisbogenbefehl. Das ist üblicherweise aus Geradenstücken angenähert. Den Bresenham müßte man vermutlich auf einem 45Grad-Segmentpunkt starten, aber das erste Stück weglassen, bis ein Schwellwert überschritten ist - den müßte man aber erst mal berechnen.
Eine Alternative zu Bresenham ist der CORDIC-Algorithmus, mit dem kann man Sinus und Cosinus berechnen, dann kann Herr Lehrer auch eine Kreisgleichung benutzen, ohne Hochsprache.
@Lehrer: Den Schüler will ich sehen, der in der 6.Klasse schon mit Sinus und Cosinus "rummacht". Trogometrie ist wohl eher Stoff ab der 8./9. Klasse (Gymnasium). In der 6. Klasse kommen so nette Sachen wie Wurzelrechnung, gemischte Brüche (oder wie die heissen) dran.
Habe mal meine alten Schulbücher angeschaut. Winkelfunktionen wurden damals in der 7 Klasse Realschule (1980, Baden- Württemberg) abgearbeitet. Ich wundere mich, dass die "Nordstaaten" heute überhaupt noch solche komplexe Sachverhalte im Lehrplan haben... ;-)
void rasterCircle(int x0, int y0, int radius) { int f = 1 - radius; int ddF_x = 0; int ddF_y = -2 * radius; int x = 0; int y = radius; setPixel(x0, y0 + radius); setPixel(x0, y0 - radius); setPixel(x0 + radius, y0); setPixel(x0 - radius, y0); while(x < y) { if(f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x + 1; setPixel(x0 + x, y0 + y); setPixel(x0 - x, y0 + y); setPixel(x0 + x, y0 - y); setPixel(x0 - x, y0 - y); setPixel(x0 + y, y0 + x); setPixel(x0 - y, y0 + x); setPixel(x0 + y, y0 - x); setPixel(x0 - y, y0 - x); } } hier nochmal die funktion in C. Aus wikipedia ;). getestet, funktioniert exzellent. viel spaß beim kreisemalen!
Die Funktion mal aber nur Vollkreise. Mal damit mal einen, der keine kompletten Kreissegmente malt.
Hab den Algorithmus auch gefunden, aber diese Routine zeichnet ja nur den Kreisumfang. Wir haben gerade ein Projekt an der Hochschule, wo wir Vollkreise (Fläche ausgemahlt) auf einem Grafikdisplay anzeigen wollen. Kann mir zufällig jemand einen C-Code empfehlen, wodurch man das realisieren könnte. Wäre super, wenn jemand antworten würde, sind grad total am Verzweifeln. Danke Im Vorraus
Im einfachsten Fall von jedem Punkt des Umfangs eine Linie zum Mittelpunkt zeichnen. Sicherlich verbesserungswürdig... ;-)
Gute Idee :-). Wenn ich den Quellcode, den Philipp Karbach gepostet habe, und einfach am Schluss den Radius dekrementiere (Radius--), und den neue Radius der Funktion nochmal übergeben in ner Schleife, bis der Radius 0 ist, würde das auch gehen?
Es gibt natürlich viele Möglichkeiten, den Kreislinienalgorithmus zum Kreisscheibenalgorithmus aufzupimpen. Hier ist die in meinen Augen fast optimale Variante. Zusätzlich zur Berechnung der Randpunkte eines Achtelkreises müssen vertikale Linien gezeichnet werden, die zusammen die Kreisfläche bilden:
1 | void vline(int x, int y1, int y2) { |
2 | int y; |
3 | |
4 | for(y=y1; y<=y2; y++) |
5 | setPixel(x, y); |
6 | }
|
7 | |
8 | void rasterDisk(int x0, int y0, int radius) { |
9 | int f = 1 - radius; |
10 | int ddF_x = 0; |
11 | int ddF_y = -2 * radius; |
12 | int x = 0; |
13 | int y = radius; |
14 | |
15 | vline(x0, y0-radius, y0+radius); |
16 | |
17 | while(x < y) { |
18 | if(f >= 0) { |
19 | vline(x0+y, y0-x, y0+x); |
20 | vline(x0-y, y0-x, y0+x); |
21 | |
22 | y--; |
23 | ddF_y += 2; |
24 | f += ddF_y; |
25 | }
|
26 | x++; |
27 | ddF_x += 2; |
28 | f += ddF_x + 1; |
29 | |
30 | vline(x0+x, y0-y, y0+y); |
31 | vline(x0-x, y0-y, y0+y); |
32 | }
|
33 | }
|
Das Implementierungsbeispiel für vline() kann für LCDs optimiert werden, da dort typischerweise bis zu 8 Pixel mit einem Zugriff gesetzt werden können. Der Algorithmus zeichnet - abhängig vom Radius - oft zwei der vertikalen Linien doppelt. Das macht ihn nicht wirklich schlecht, aber es ist unschön. Auch der Kreislinienalgorithmus hat diese Schwäche, nur fällt sie dort nicht so arg ins Gewicht, da dort nur ein paar (4 oder 8) Pixel doppelt gezeichnet werden. Beides kann man verbessern, doch habe ich im Moment keinen Kopf dazu ;-)
Danke für die schnelle Hilfe. Würde das auch funktionieren?
1 | void rasterCircle(int x0, int y0, int radius) |
2 | { //Beginn Funktion |
3 | while(radius > 0) |
4 | { //Beginn While-Schleife 1 |
5 | int f = 1 - radius; |
6 | int ddF_x = 0; |
7 | int ddF_y = -2 * radius; |
8 | int x = 0; |
9 | int y = radius; |
10 | |
11 | setPixel(x0, y0 + radius); |
12 | setPixel(x0, y0 - radius); |
13 | setPixel(x0 + radius, y0); |
14 | setPixel(x0 - radius, y0); |
15 | |
16 | while(x < y) |
17 | { //Beginn While-schleife 2 |
18 | if(f >= 0) |
19 | { //Beginn If-Schleife |
20 | y--; |
21 | ddF_y += 2; |
22 | f += ddF_y; |
23 | } //Ende If-Schleife |
24 | x++; |
25 | ddF_x += 2; |
26 | f += ddF_x + 1; |
27 | |
28 | setPixel(x0 + x, y0 + y); |
29 | setPixel(x0 - x, y0 + y); |
30 | setPixel(x0 + x, y0 - y); |
31 | setPixel(x0 - x, y0 - y); |
32 | setPixel(x0 + y, y0 + x); |
33 | setPixel(x0 - y, y0 + x); |
34 | setPixel(x0 + y, y0 - x); |
35 | setPixel(x0 - y, y0 - x); |
36 | } //Ende While-Schleife 2 |
37 | radius--; |
38 | rasterCircle(x0,y0,radius); |
39 | } //Ende While-Schleife 1 |
40 | }
|
Damit er den Umfang zeichnet + Vertikallinien müsste der Code dann folgendermaßen aussehen oder?
1 | void vline(int x, int y1, int y2) { |
2 | int y; |
3 | |
4 | for(y=y1; y<=y2; y++) |
5 | setPixel(x, y); |
6 | }
|
7 | |
8 | |
9 | |
10 | void rasterCircle(int x0, int y0, int radius) |
11 | {
|
12 | int f = 1 - radius; |
13 | int ddF_x = 0; |
14 | int ddF_y = -2 * radius; |
15 | int x = 0; |
16 | int y = radius; |
17 | |
18 | setPixel(x0, y0 + radius); |
19 | setPixel(x0, y0 - radius); |
20 | setPixel(x0 + radius, y0); |
21 | setPixel(x0 - radius, y0); |
22 | |
23 | vline(x0, y0-radius, y0+radius); |
24 | |
25 | while(x < y) |
26 | {
|
27 | if(f >= 0) |
28 | {
|
29 | vline(x0+y, y0-x, y0+x); |
30 | vline(x0-y, y0-x, y0+x); |
31 | y--; |
32 | ddF_y += 2; |
33 | f += ddF_y; |
34 | }
|
35 | x++; |
36 | ddF_x += 2; |
37 | f += ddF_x + 1; |
38 | |
39 | setPixel(x0 + x, y0 + y); |
40 | setPixel(x0 - x, y0 + y); |
41 | setPixel(x0 + x, y0 - y); |
42 | setPixel(x0 - x, y0 - y); |
43 | setPixel(x0 + y, y0 + x); |
44 | setPixel(x0 - y, y0 + x); |
45 | setPixel(x0 + y, y0 - x); |
46 | setPixel(x0 - y, y0 - x); |
47 | |
48 | vline(x0+x, y0-y, y0+y); |
49 | vline(x0-x, y0-y, y0+y); |
50 | }
|
51 | }
|
Es dürfte relativ sinnfrei sein, zuerst die Randpixel zu malen, wenn dann sowieso eine Linie zu/von diesem Randpixel geht. Du solltest dir erst mal die Theorie zu Bresenham reinziehen. Zuerst der Linen - Bresenham (um mit dem grundsätzlichen Verfahren warm zu werden) und dann mit der Variation die auf Kreise losgelassen wird.
> Danke für die schnelle Hilfe. Würde das auch funktionieren?
Der Aufruf von rasterCircle am Ende der While-Schleife scheint doppelt
gemoppelt. Außerdem kann ich mir vorstellen (hab's nicht ausprobiert),
dass die Kreisfläche mit dem Verfahren nicht vollständig gefüllt wird,
da in den Regionen, wo die Linie schräg verläuft, der Pixelabstand > 1
ist. Dadurch könnte die Fläche im Bereich der beiden 45°-Achsen Löcher
aufweisen. Aber probier's doch einfach mal aus.
Außerdem wird für jedes gesetzte Pixel deutlich mehr gerechnet als für
das Zeichnen von vertikalen Linien.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.