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?
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.
achja und defines am anfang einer funktion, das ist ziemlich hässlich, schreib sie lieber davor!
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.
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.
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.
bis auf ein paar Punkte stimmt es jetzt. Aber irgendwo gibt es noch punkte die daneben liegen.
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.