Forum: Mikrocontroller und Digitale Elektronik Darstellung kreis oder kurve auf GLCD


von HerrmannA (Gast)


Lesenswert?

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

von bla (Gast)


Lesenswert?

Viertelkreis:

y = sqrt(r^2 - x^2) und den Rest spiegeln.

von D. W. (dave) Benutzerseite


Lesenswert?


von Rahul (Gast)


Lesenswert?

nach "Bresenham Algorithmus" suchen...

von Christoph Kessler (db1uq) (Gast)


Angehängte Dateien:

Lesenswert?

ich habs zwar schonmal gepostet, aber hier ist mein Bresenham-Kreis in
AVR-Assembler

von Lehrer (Gast)


Lesenswert?

Wenn Du einen Pixel setzen kannst, und Du in der Schule (6 Klasse ?)
aufgepasst hast, dann solltest Du auch einen Kreis ausgeben können!

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

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

von Rahul (Gast)


Lesenswert?

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")?

von Christoph Kessler (db1uq) (Gast)


Lesenswert?

Das habe ich auch tunlichst vermieden, meine Routine zeichnet nur ganze
Achtel.

von Ralf (Gast)


Lesenswert?

> 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

von Rahul (Gast)


Lesenswert?

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.

von Lehrer (Gast)


Lesenswert?

@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...

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

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.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

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.

von Laeubi (Gast)


Lesenswert?

Oder Tabellen für Sin/Cos ;)

von Rahul (Gast)


Lesenswert?

@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.

von Rahul (Gast)


Lesenswert?


von Lehrer (Gast)


Lesenswert?

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... ;-)

von Philipp Karbach (Gast)


Lesenswert?

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!

von Rahul (Gast)


Lesenswert?

Die Funktion mal aber nur Vollkreise. Mal damit mal einen, der keine
kompletten Kreissegmente malt.

von Atomica (Gast)


Lesenswert?

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

von l00k (Gast)


Lesenswert?

Im einfachsten Fall von jedem Punkt des Umfangs eine Linie zum 
Mittelpunkt zeichnen. Sicherlich verbesserungswürdig... ;-)

von Atomica (Gast)


Lesenswert?

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?

von yalu (Gast)


Lesenswert?

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 ;-)

von Atomica (Gast)


Lesenswert?

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
  }

von Atomica (Gast)


Lesenswert?

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
  }

von Karl H. (kbuchegg)


Lesenswert?

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.

von yalu (Gast)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.