Entwickler-Ecke

Sonstiges (Delphi) - Objektrotation in Abhängigkeit


ZeitGeist87 - Fr 16.05.14 08:46
Titel: Objektrotation in Abhängigkeit
Guten Morgen zusammen,

ich sitze seit gestern Nachmittag an einem Problem, bei dessen Lösung ich auf dem Schlauch sitze.
Mir fehlt hier ein Denkanstoß.

Zum Problem:

Gegeben ist ein Objekt: siehe Vorlage.
Dieses Besteht in diesem Beispiel aus 4 Bildern (TImage). Eins für die Form und jeweils ein TImage für die Markierung (rot, grün und blau).

Das Objekt wird wird auf einer Scrollbox platziert und soll nun rotiert werden. Soweit alles kein Problem, die Form wird rotiert, 90° im Uhrzeigersinn.

Jetzt geht mein eigentliches Problem los: Die Markierungen an den definierten Positionen müssen sich um 90° mit rotieren.

Folgenden Lösungsansatz hab ich, zumindest dachte ich, dass ich auf Basis einer Rotation eines Punktes arbeite:

Ich nehme mir vom entsprechenden Marker (rot, grün und dann blau) jeweils TOP/LEFT und betrachte diesen als Koordinate im absoluten Raum und wende dann einfach die Formel

X2 = +(X1*cos(90)) + (Y1*sin(90))
Y2 = -(X1*sin(90)) + (Y1*cos(90))


darauf an.

Allerdings rotiert das die Objekte irgendwo hin.

Dann kam mir die Idee, dass ich vom Mittelpunkt der Form ausgehen sollte und diese darum rotiere?

Ich wäre froh um eure Hilfe.

Danke und schönen Freitag,
Stefan

Crosspost in der DP [http://www.delphipraxis.net/180378-objektrotation-abhaengigkeit.html#post1259019]


Mathematiker - Fr 16.05.14 09:16

Hallo,
user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings rotiert das die Objekte irgendwo hin.
Dann kam mir die Idee, dass ich vom Mittelpunkt der Form ausgehen sollte und diese darum rotiere?

Einen Punkt korrekt Drehen um einen beliebigen Punkt P geht normalerweise in 3 Schritten.
Zuerst wird eine Verschiebung durchgeführt, die P in den Ursprung transformiert, danach wird um (0;0) gedreht und anschließend die Translation rückgängig gemacht.
Dreht sich Deine Form um ihren Mittelpunkt, so ist dieser Mittelpunkt auch der Drehpunkt für Deine anderen Objekte.

Beste Grüße
Mathematiker


ZeitGeist87 - Fr 16.05.14 09:26

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings rotiert das die Objekte irgendwo hin.
Dann kam mir die Idee, dass ich vom Mittelpunkt der Form ausgehen sollte und diese darum rotiere?

Einen Punkt korrekt Drehen um einen beliebigen Punkt P geht normalerweise in 3 Schritten.
Zuerst wird eine Verschiebung durchgeführt, die P in den Ursprung transformiert, danach wird um (0;0) gedreht und anschließend die Translation rückgängig gemacht.
Dreht sich Deine Form um ihren Mittelpunkt, so ist dieser Mittelpunkt auch der Drehpunkt für Deine anderen Objekte.

Beste Grüße
Mathematiker


Klingt wunderbar. Nur muss ich sagen, bin mathematisch nicht so bewandert.

Könntest du mir hier eine Hilfestellung geben, wie ich das in Delphi bewerkstellige?
Ich hab noch nie mit Matrizen gerechnet...


Mathematiker - Fr 16.05.14 09:34

Hallo,
user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Könntest du mir hier eine Hilfestellung geben, wie ich das in Delphi bewerkstellige?

Beispiel: x1,y1 sollen um xp,yp gedreht werden.

Quelltext
1:
2:
3:
4:
5:
1. xh := x1-xp;  yh := y1-xp;
2. xh, yh mit Deinen Gleichungen drehen, also
X2 := +(xh*cos(90)) + (yh*sin(90)); 
Y2 := -(xh*sin(90)) + (yh*cos(90)); 
3. x1 := x2+xp; y1 := y2+yp;

Übrigens sind bei einem 90°-Winkel cos 90° = 0 und sin 90° = 1. Damit kannst Du es auf

Quelltext
1:
2:
3:
4:
5:
1. xh := x1-xp;  yh := y1-xp;
2. xh, yh mit Deinen Gleichungen drehen, also
X2 := yh; 
Y2 := -xh; 
3. x1 := x2+xp; y1 := y2+yp;

reduzieren und weiter zusammenfassen.

Quelltext
1:
2:
X2 := y1-xp; Y2 := -x1+xp; 
x1 := x2+xp; y1 := y2+yp;

Beste Grüße
Mathematiker


ZeitGeist87 - Fr 16.05.14 10:55

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Könntest du mir hier eine Hilfestellung geben, wie ich das in Delphi bewerkstellige?

Beispiel: x1,y1 sollen um xp,yp gedreht werden.

Quelltext
1:
2:
3:
4:
5:
1. xh := x1-xp;  yh := y1-xp;
2. xh, yh mit Deinen Gleichungen drehen, also
X2 := +(xh*cos(90)) + (yh*sin(90)); 
Y2 := -(xh*sin(90)) + (yh*cos(90)); 
3. x1 := x2+xp; y1 := y2+yp;

Übrigens sind bei einem 90°-Winkel cos 90° = 0 und sin 90° = 1. Damit kannst Du es auf

Quelltext
1:
2:
3:
4:
5:
1. xh := x1-xp;  yh := y1-xp;
2. xh, yh mit Deinen Gleichungen drehen, also
X2 := yh; 
Y2 := -xh; 
3. x1 := x2+xp; y1 := y2+yp;

reduzieren und weiter zusammenfassen.

Quelltext
1:
2:
X2 := y1-xp; Y2 := -x1+xp; 
x1 := x2+xp; y1 := y2+yp;

Beste Grüße
Mathematiker



Quelltext
1:
1. xh := x1-xp;  yh := y1-xp;                    


Muss das nicht yh := y1-yp lauten?


Mathematiker - Fr 16.05.14 11:43

user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Muss das nicht yh := y1-yp lauten?

Muss es, natürlich. :autsch:
Sorry

Mathematiker


ZeitGeist87 - Fr 16.05.14 11:48

user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Muss das nicht yh := y1-yp lauten?

Muss es, natürlich. :autsch:
Sorry

Mathematiker


Kein Problem. Man soll ja auch das Hirn einschalten und nicht alles via Copy&Paste übernehmen ;-)

Ich hab es jetzt mal implementiert, allerdings glaube ich, hab ich noch einen..Schwachpunkt.


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:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
unit unit_main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Imaging.jpeg, Vcl.ExtCtrls,
  Vcl.Imaging.pngimage, Vcl.StdCtrls, Generics.Collections, System.Math;

type
  RMarker = record
    Top: Integer;
    Left: Integer;
    Width: Integer;
    Height: Integer;
  end;

type
  TMarker = TDictionary<TImage, RMarker>;

type
  Tform_main = class(TForm)
    Image1: TImage;
    img1: TImage;
    Button1: TButton;
    Image2: TImage;
    shape_mittelpunkt: TShape;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    fRotationCount: Integer;

    fMarker: TMarker;

    fMarker1Left, fMarker1Top, fMarker1Width, fMarker1Height: Integer;
  public
    { Public-Deklarationen }
  end;

var
  form_main: Tform_main;

implementation

{$R *.dfm}

procedure DreheBmp(Grad: Word; SourceBmp, DestBmp: TBitmap);
var
  Points: array [0 .. 2of TPoint;
  Winkel: Double;
  X1, X2, Y1, Y2: Integer;
begin
  if Grad <= 360 then
  begin
    Winkel := (Grad - Grad div 90 * 90) / 180 * pi;
    X1 := Round(SourceBmp.Width * sin(Winkel));
    X2 := Round(SourceBmp.Width * cos(Winkel));
    Y2 := Round(SourceBmp.Height * sin(Winkel));
    Y1 := Round(SourceBmp.Height * cos(Winkel));
    Case Grad of
      0 .. 89360:
        begin
          Points[1] := Point(X2, 0); // rechts oben
          Points[0] := Point(0, X1); // links oben
          Points[2] := Point(Y2, Y1 + X1); // links unten
          DestBmp.Width := X2 + Y2;
          DestBmp.Height := Y1 + X1;
        end;
      90 .. 179:
        begin
          Points[1] := Point(0, Y2); // rechts oben
          Points[0] := Point(X1, Y2 + X2); // links oben
          Points[2] := Point(X1 + Y1, X2); // links unten
          DestBmp.Width := Y1 + X1;
          DestBmp.Height := X2 + Y2;
        end;
      180 .. 269:
        begin
          Points[1] := Point(Y2, X1 + Y1); // rechts oben
          Points[0] := Point(Y2 + X2, Y1); // links oben
          Points[2] := Point(X2, 0); // links unten
          DestBmp.Width := X2 + Y2;
          DestBmp.Height := Y1 + X1;
        end;
      270 .. 359:
        begin
          Points[1] := Point(X1 + Y1, X2); // rechts oben
          Points[0] := Point(Y1, 0); // links oben
          Points[2] := Point(0, Y2); // links unten
          DestBmp.Width := Y1 + X1;
          DestBmp.Height := X2 + Y2;
        end;
    end;
    PlgBlt(DestBmp.Canvas.Handle, Points, SourceBmp.Canvas.Handle, 00,
      SourceBmp.Width, SourceBmp.Height, 000);
  end;
end;

procedure Tform_main.Button1Click(Sender: TObject);
var
  bmp1, bmp2: TBitmap;

  xp, yp: Integer;
  X1, Y1: Integer;
  X2, Y2: Integer;
  xh, yh: Integer;
begin
  bmp1 := TBitmap.Create;
  bmp1.Assign(Image1.Picture.Graphic);
  bmp2 := TBitmap.Create;

  inc(fRotationCount);

  // Mittelpunkt des T-Stücks
  xp := (Image1.Left + Image1.Width) - (Image1.Width div 2);
  yp := (Image1.Top + Image1.Height) - (Image1.Height div 2);

  // Drehpunkt TOP/LEFT T-Stück (DEBUG)
  // xp := Image1.Left;
  // yp := Image1.Top;

  // TOP/LEFT des Markers
  X1 := img1.Left;
  Y1 := img1.Top;

  // Differenz zum Mittelpunkt
  xh := X1 - xp;
  yh := Y1 - yp;

  X2 := +Round((xh * cos(DegToRad(90))) + (yh * sin(DegToRad(90))));
  Y2 := -Round((xh * sin(DegToRad(90))) + (yh * cos(DegToRad(90))));

  X1 := X2 + xp;
  Y1 := Y2 + yp;

  X2 := Y1 - xp;
  Y2 := -X1 + xp;
  X1 := X2 + xp;
  Y1 := Y2 + yp;

  // Zuweisung neuer Koordinaten
  img1.Left := X1;
  img1.Top := Y2;

  // Drehe T-Stück
  // DreheMarker(img1);
  DreheBmp(90, bmp1, bmp2);
  Image1.Picture.Assign(bmp2);

  // Mittelpunkt nach Drehung holen (DEBUG)
  xp := (Image1.Left + Image1.Width) - (Image1.Width div 2);
  yp := (Image1.Top + Image1.Height) - (Image1.Height div 2);

  // Objektmittelpunkt anzeigen (DEBUG)
  shape_mittelpunkt.Left := xp - shape_mittelpunkt.Width div 2;
  shape_mittelpunkt.Top := yp - shape_mittelpunkt.Height div 2;

end;

end.


Mathematiker - Fr 16.05.14 13:53

Hallo,
user profile iconZeitGeist87 hat folgendes geschrieben Zum zitierten Posting springen:
Ich hab es jetzt mal implementiert, allerdings glaube ich, hab ich noch einen..Schwachpunkt.

Kannst Du eine Exe anhängen.
Mit meinem Delphi 5 kann ich es nicht übersetzen und sehe deshalb nicht, wo der "Schwachpunkt" ist.

Beste Grüße
Mathematiker


ZeitGeist87 - Fr 16.05.14 14:05

Na klar ;-)

Ich kann es auch schnell in D7 tippen.