www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Polygon auf LCD drehen


Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche ein Polygon auf dem LCD zu drehen.
Ich habe verschiedene Vektoren definiert die dann um einen bestimmten 
Winkel gedreht werden. Im Beispiel ist das ein Pfeil der aus mehreren 
Linien definiert ist.
Das Ganze dreht sich zwar, ergibt aber keinen gefüllten Pfeil da es 
irgendwo rundungsfehler gibt.
Das Display ist ein 128x64.

//Anfangs und Endkoordinaten der Linien, ergibt zusammengesetzt einen 
Kompasspfeil
s08 
px[]={4,4,3,3,2,2,1,1,0,0,-1,-1,-2,-2,-3,-3,-4,-4},py[]={6,8,2,7,-2,6,-7 
,5,-9,4,-7,5,-2,6,2,7,6,8};


rotate (px,py,30);//Aufruf zum drehen 30°

void rotate (s08* px,s08* py,u16 winkel)
{
 #define POINTS 18
 #define MITTEX 95
 #define MITTEY 31

 double arcus = (2  PI  winkel) / 360;
 float cosinus = cos( arcus );
 float sinus = sin( arcus );
 float x,y;

 for (u08 i = 0; i < POINTS; i++ )
 {
  x = px[i];
  y = py[i];
  px[i] = (cosinus  x - sinus  y);
  py[i] = (sinus * x + cosinus * y);
 }
 for (u08 i = 0; i < POINTS; i+=2 )
 DrawLine(px[i]+MITTEX,py[i]+MITTEY,px[i+1]+MITTEX,py[i+1]+MITTEY,BLACK);
}

kann mir jemand helfen den Fehler der Berechnung zu finden?

Autor: Philipp Karbach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nur eine annahme aber vielleicht bist du zu genau mit deiner rechnung, 
die line funktion arbeitet ja nur mit integern weil es keine halben 
pixel gibt, da wird natürlich gerundet.

Autor: Philipp Karbach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
achja und defines am anfang einer funktion, das ist ziemlich hässlich, 
schreib sie lieber davor!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael wrote:

> kann mir jemand helfen den Fehler der Berechnung zu finden?

Deine Rotations-Berechnung an und für sich ist korrekt.
Allerdings ist deine Annahme falsch, dass 2 pixelparallele
Linien nach einer Drehung immer noch pixelparallel sind.

Das Beste wäre es, wenn du dir eine Füllfunktion für deinen
Pfeil schreiben würdest, die nicht davon ausgeht, dass irgendwelche
Begrenzungslinien exakt senkrecht oder waagrecht sind. Das ist
zwar etwas Aufwand, wenn du allerdings deinen Pfeil in lauter
Dreiecke aufteilst und mit einer generellen Dreiecks-füll-funktion
arbeitest, sollte das machbar sein.

Eventuell könnte dich in der jetzigen Version noch eine Rundungs-
korrektur retten:

  px[i] = (int)((cosinus  x - sinus  y) + 0.5);
  py[i] = (int)((sinus * x + cosinus * y) + 0.5);

aber grosse Hoffnungen würde ich nicht darauf setzen.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Rundung mit +0,5 habe ich schon probiert, das hilft nur wenig.
Eine Füllfunktion für Dreiecke wäre sicherlich richtig, allerdings habe 
ich noch nichts (für mich) brauchbares im Netz gefunden.

ist diese Funktion geeignet?

#define BOARD WIDTH  10
#define BOARD HEIGHT 20

typedef struct MAP
{
  unsigned char b[BOARD HEIGHT][BOARD WIDTH];
} MAP;

static void flood_loop(MAP *map, int x, int y, unsigned int dst_c, 
unsigned int src_c)
{
  int fillL, fillR, i;
  int in_line = 1;

  /* find left side, filling along the way */
  fillL = fillR = x;
  while(in_line)
  {
    map->b[y][fillL] = dst_c;
    fillL--;
    in_line = (fillL < 0) ? 0 : (map->b[y][fillL] == src_c);
  }
  fillL++;

  /* find right side, filling along the way */
  in_line = 1;
  while(in_line)
  {
    map->b[y][fillR] = c;
    fillR++;
    in_line = (fillR > 9) ? 0 : (map->b[y][fillR] == fillC);
  }
  fillR--;

  /* search top and bottom */
  for(i = fillL; i <= fillR; i++)
  {
    if(y > 0 && map->b[y - 1][i] == fillC)
        flood_loop(map, i, y - 1, c, fillC);
    if(y < BOARD HEIGHT && map->b[y + 1][i] == fillC)
        flood_loop(map, i, y + 1, c, fillC);
  }
}

void flood_fill(MAP *map, int x, int y, unsigned int c)
{
  flood_loop(map, x, y, c, map->b[y][x]);
  map->b[y][x] = c;  /* some buggy optimizers needed this line */
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael wrote:
> Die Rundung mit +0,5 habe ich schon probiert, das hilft nur wenig.

Dachte ich mir schon.

> Eine Füllfunktion für Dreiecke wäre sicherlich richtig, allerdings habe
> ich noch nichts (für mich) brauchbares im Netz gefunden.

zb hier
http://www.gamedev.net/community/forums/topic.asp?...

Eine generelle Füll Funktion für Dreicke ist nicht weiter
schwer. Das sollte eigentlich jeder, der Graphik Programmierung
macht, ohne gröbere Probleme hinbekommen.

>
> ist diese Funktion geeignet?

Das sieht mir mehr nach einem generellem Flood Fill aus.
Ist für deine Zwecke nicht unbedingt das Wahre, da du damit
eine allgemeine Füllfunktion hast, die du so (zumindest für
diesen Zweck) nicht brauchst.
Ausserdem musst du zuerst mit Linien deinen Pfeil aufmalen um ihn
nachher mit dem Flood Fill auszumalen.
Aussderdem gibt es Schwierigkeiten, wenn der Pfeil nicht für sich
alleine steht, sondern zb eine Linie unter dem Pfeil durchläuft.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das habe ich jetzt implementiert, hat aber auch noch einen Fehler den 
ich noch nicht gefunden habe:
//Dreieck auffüllen drei Eckpunkte werden übergeben

void trianglefiller (s08 ax,s08 ay,s08 bx,s08 by,s08 cx,s08 cy)
{
 s08 dx1,dx2,dx3,temp;

 //Eckpunkte sortieren mit kleinstem y-wert als a
 if(ay>=by){temp=by;by=ay;ay=temp;temp=bx;bx=ax;ax=temp;}
 if(ay>=cy){temp=cy;cy=ay;ay=temp;temp=cx;cx=ax;ax=temp;}
 if(by>=cy){temp=cy;cy=by;by=temp;temp=cx;cx=bx;bx=temp;}

 A.x=ax;
 A.y=ay;
 B.x=bx;
 B.y=by;
 C.x=cx;
 C.y=cy;

  if (B.y-A.y > 0) dx1=(B.x-A.x)/(B.y-A.y); else dx1=0;
  if (C.y-A.y > 0) dx2=(C.x-A.x)/(C.y-A.y); else dx2=0;
  if (C.y-B.y > 0) dx3=(C.x-B.x)/(C.y-B.y); else dx3=0;

  S=E=A;
  if(dx1 > dx2)
    {
    for(;S.y<=B.y;S.y++,E.y++,S.x+=dx2,E.x+=dx1)
      DrawLine(S.x,S.y,E.x,S.y,BLACK);
    E=B;
    for(;S.y<=C.y;S.y++,E.y++,S.x+=dx2,E.x+=dx3)
      DrawLine(S.x,S.y,E.x,S.y,BLACK);
  }
    else
    {
    for(;S.y<=B.y;S.y++,E.y++,S.x+=dx1,E.x+=dx2)
      DrawLine(S.x,S.y,E.x,S.y,BLACK);
    S=B;
    for(;S.y<=C.y;S.y++,E.y++,S.x+=dx3,E.x+=dx2)
      DrawLine(S.x,S.y,E.x,S.y,BLACK);
  }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael wrote:
> das habe ich jetzt implementiert, hat aber auch noch einen Fehler den
> ich noch nicht gefunden habe:

(Ohne das jetzt ausprobiert zu haben)
Dein Problem wird wohl damit zu tun haben, dass dx1, dx2, dx3
float sein sollten und keine Intger Typen.
Falls du es noch nicht bemerkt hast, aber die dx stellen die
Steigungen der Dreieckskanten dar und die sind nun mal selten
ganzzahlig.

Bei deinen Zahlenwerten könnte man allerdings mal überprüfen
ob man anstelle von float nicht auch eine Fixpunktarithmetik
nehmen kann.

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bis auf ein paar Punkte stimmt es jetzt.
Aber irgendwo gibt es noch punkte die daneben liegen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.