Autor Beitrag
JayEff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: So 09.10.05 17:28 
Hi Leute. Hab die Suche grade ne Stunde lang bemüht und hab tatsächlich was gefunden:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
procedure RotateBitmapA(var Bitmap: TBitmap; const ADegrees: Cardinal;
  const clBack: TColor);
const
  MaxPixelCount   =  32768;

type
  pRGBArray  =  ^TRGBArray;    // Use SysUtils.pByteArray for 8-bit color   
  TRGBArray  =  array [0..MaxPixelCount-1of TRGBTriple;

var   
  cosTheta      :  DOUBLE;
  i             :  INTEGER;   
  iRotationAxis :  INTEGER;   
  iOriginal     :  INTEGER;
  iPrime        :  INTEGER;   
  iPrimeRotated :  INTEGER;   
  j             :  INTEGER;
  jRotationAxis :  INTEGER;   
  jOriginal     :  INTEGER;   
  jPrime        :  INTEGER;
  jPrimeRotated :  INTEGER;   
  RowOriginal   :  pRGBArray;   
  RowRotated    :  pRGBArray;
  sinTheta      :  DOUBLE;   
  Theta         :  DOUBLE;       // radians   

  OldHeight     :  INTEGER;   
  OldWidth      :  INTEGER;   
  NewWidth      :  INTEGER;
  NewHeight     :  INTEGER;   
  BitmapRotated :  TBitmap;   
  Back          :  RGBTriple;   
begin   
  Back.rgbtBlue := GetBValue(clBack);
  Back.rgbtGreen := GetGValue(clBack);   
  Back.rgbtRed := GetRValue(clBack);   

  Theta := ADegrees * PI /180;
  sinTheta := Sin(Theta);   
  cosTheta := Cos(Theta);

  OldWidth := Bitmap.Width;   
  OldHeight := Bitmap.Height;

  //An easy way to calculate the non-clipping rectangle   
  NewWidth := Abs(Round(OldHeight * sinTheta)) + Abs(Round(OldWidth *
                cosTheta));   
  NewHeight := Abs(Round(OldWidth * sinTheta)) + Abs(Round(OldHeight *   
                 cosTheta));   

  BitmapRotated := TBitmap.Create;
  BitmapRotated.Width  := NewWidth;   
  BitmapRotated.Height := NewHeight;   
  BitmapRotated.PixelFormat := pf24bit;   
  BitmapRotated.Canvas.Brush.Color := clBack;   
  BitmapRotated.Canvas.FillRect(Rect(00, NewWidth, NewHeight));
//  BitmapRotated.Canvas.FillRect(Rect(0, 0, NewWidth, NewHeight));   

  iRotationAxis := OldWidth div 2;   
  jRotationAxis := OldHeight div 2;   

  // Step through each row of rotated image.   
  for J := BitmapRotated.Height - 1 downto 0 do begin   
    RowRotated  := BitmapRotated.Scanline[J];   
    // Assume the bitmap has an even number of pixels in both dimensions and   
    // the axis of rotation is to be the exact middle of the image -- so this
    // axis of rotation is not at the middle of any pixel.   

    // The transformation (i,j) to (iPrime, jPrime) puts the center of each   
    // pixel at odd-numbered coordinates.  The left and right sides of each   
    // pixel (as well as the top and bottom) then have even-numbered coordinates.

    // The point (iRotationAxis, jRotationAxis) identifies the axis of rotation.   

    // For a 640 x 480 pixel image, the center point is (320, 240).  Pixels   
    // numbered (index i) 0..319 are left of this point along the "X" axis and
    // pixels numbered 320..639 are right of this point.  Likewise, vertically   
    // pixels are numbered (index j) 0..239 above the axis of rotation and   
    // 240..479 below the axis of rotation.   

    // The subtraction (i, j) - (iRotationAxis, jRotationAxis) moves the axis
    // of rotation from (i, j) to (iRotationAxis, jRotationAxis), which is the   
    // center of the bitmap in this implementation.   

    // offset origin by the growth factor (NewHeight - OldHeight) div 2   
    jPrime := 2*(J - (NewHeight - OldHeight) div 2 - jRotationAxis) + 1 ;

    for I := NewWidth - 1 downto 0 do begin   
      // offset origin by the growth factor (NewWidth - OldWidth) div 2   
      iPrime := 2*(I - (NewWidth - OldWidth) div 2 - iRotationAxis) + 1;   

      // Rotate (iPrime, jPrime) to location of desired pixel
      // Note:  There is negligible difference between floating point and
      // scaled integer arithmetic here, so keep the math simple (and readable).   
      iPrimeRotated := Round(iPrime * CosTheta - jPrime * sinTheta);
      jPrimeRotated := Round(iPrime * sinTheta + jPrime * cosTheta);   

      // Transform back to pixel coordinates of image, including translation
      // of origin from axis of rotation to origin of image.
      iOriginal := (iPrimeRotated - 1div 2 + iRotationAxis;
      jOriginal := (jPrimeRotated - 1div 2 + jRotationAxis;

      // Make sure (iOriginal, jOriginal) is in BitmapOriginal.  If not,   
      // assign blue color to corner points.
      if   (iOriginal >= 0and (iOriginal <= Bitmap.Width - 1)
      and  (jOriginal >= 0and (jOriginal <= Bitmap.Height - 1then begin   
        // Assign pixel from rotated space to current pixel in BitmapRotated
        RowOriginal := Bitmap.Scanline[jOriginal];
        RowRotated[I]  := RowOriginal[iOriginal]   
      end
{      else
        RowRotated[I] := Back;   }
   
    end;
  end;
  Bitmap.Assign(BitmapRotated);
  BitmapRotated.Free;
end;

Na Klasse. Nach vielem Rumprobieren, bei dem ich des öfteren nur leere Images bekommen habe (Image1.Canvas.Draw(1,1,bit) wobei bit eine eigentlich gedrehte Bitmap ist), habe ich nun Folgendes getippselt:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button1Click(Sender: TObject);
var bit:TBitmap;
begin
bit:=TBitmap.Create;
bit.LoadFromFile('C:\bildchen.bmp');
Rotatebitmapa(bit,50,clWhite);
bit.SaveToFile('C:\bildchen.bmp');
bit.Free;
end;

klappt ganz gut, nur... das ergebnis. wenns am anfang sowas ist:
user defined image
passiert das:
einmal drehen:
user defined image
zweimal drehen:
user defined image
10 mal drehen:
jayy.de/10mal.JPG(ist zu groß...)
Ihr seht: Die Bitmap wird größer und ganz grieselig. Was kann man da machen?? gibt es keinen Algorithmus, der mir ein Ergebnis liefert, das genauso groß ist wie das alte, und auch nach mehrmaligem Drehen gleich bleibt? gut, das mehrmalige drehen ließe sich umgehen in dem man immer von ursprünglichen Image ausgeht und eine andere gradzahl benutzt, anders wirds wohl eh nicht gehen.

Zusammenfassung: Was ich brauche: Eine kleine Spielfigur in einer Image komponente oder ähnlichem Drehen. Was nicht klappt: Figur wird griselig, und nicht auf dem Image angezeigt, Image wird leer.

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: So 09.10.05 20:28 
Drehe doch immer das Original! Damit sollten die Ergebnisse in dem Fall so optimal wie möglich sein. Um es besser hinbekommen zu können müsstest du den Algo so umbauen, dass die Randpixel interpoliert werden. Die dürften dann transparent sein und somit hast du dein ganzes System ausgebremst. Aber auch dann solltest du auf die originale zurückgreifen, da durch jede Drehungen das Bild verändert wird.

Du kannst entweder auf so etwas wie Graphics32 umsteigen. Damit bleibst du aber auf der Softwarevariante was immer einen gewissen Geschwindigkeitsnachteil hat. Oder aber du steigst auf eine hardwarebeschleunigte Variante um. Im persönlich würde dafür OpenGL empfehlen.

[edit] habe irgendwie überlesen, dass es sich um eine Spielfigur handelt. Wenn du vor hast ein Spiel zu machen würde ich dir in jedem Fall raten dir etwas anderes zu überlegen. Mit einem TImage und dem manuellen Rotieren dürftest du da recht schnell an die Grenzen des Machbarem gelangen.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
JayEff Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Mo 10.10.05 17:42 
Es wird ein dermaßen simples Spiel ^^ Kleine Vektorberechnungen im zweidimensionalen mit Vogelperspektive... ich könnte die Spielfiguren in eine TImageList laden, also zu Programmstart 36 mal drehen und zwar immer um 10° mehr, so stand es in einem anderen Thread... Nur eines: interpolieren??? muss ich gleich mal danach Googlen. Bringt das dann am Ende den Effekt, dass das gesamte Bild NICHT größer wird, als es vorher war? :) das wär schonmal ein Fortschritt ^^

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Di 11.10.05 09:08 
Also du solltest IMMER um das Originalbild drehen. Interpolieren x 36 sieht auch bescheiden aus. Wobei du das Problem haben dürftest, dass die Ränder deiner Figut auch weich würden. Und die Ränder weich zu zeichnen würde mehr oder weniger darauf hin hinaus laufen, dass du jedes Pixel einzen zeichnen müsstest. Was natürlich alles Andere als einfach ist.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.