Polygon auf LCD drehen

Gast #634123
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?
Gast
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.
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.
Gast
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 */
}
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?topic_id=256968

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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 19 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.