Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Windmühle, bei der die Flügelanzahl variabel ist (https://www.delphipraxis.net/102420-windmuehle-bei-der-die-fluegelanzahl-variabel-ist.html)

spox 28. Okt 2007 15:09


Windmühle, bei der die Flügelanzahl variabel ist
 
Ich bin zurzeit an einer Windmühle, bei dem die Postition, Flügelanzahl und Höhe der Mühle variabel ist. Das "Haus" der Mühle habe ich schon fertig, nur komme ich bei den variablen Flügeln nicht weiter:
Delphi-Quellcode:
unit muehleU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

const
 pi=3.1415;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure Muehle(anzahl,hoehe,x,y:integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 Muehle (4,150,50,50);
end;

procedure TForm1.Muehle (anzahl,hoehe,x,y:integer);
var flange,nr,bm,x2,y2:integer;
begin
 with Image1.Canvas do
  begin
   moveTo (x,y);
   rectangle (x,y,x+round(hoehe/5),hoehe);
   moveTo (x+(round(hoehe/5)DIV 2),y+10);
   x2:= x+(round(hoehe/5)DIV 2);
   y2:= y+10;
   flange:= hoehe DIV 2 ;
   bm:= round((2*pi) / anzahl);
   for nr:= 1 to anzahl do
   begin
   lineTo (round(flange*cos(bm*nr)+(hoehe DIV 10)),round(-flange*sin(bm*nr)+60));
   moveTo (x2,y2);
   end;
  end;
end;

end.
Habt ihr Tipps bzw. Lösungen?

Apollonius 28. Okt 2007 15:14

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Ich denke, da kann man nur trigonometrisch rangehen. Also mit dem Anfangswinkel starten, den Endpunkt des Flügels ausrechnen (sin/cos), den Winkel ändern usw.
Delphi-Quellcode:
FluegelEndPunkt.X:=Drehpunkt.X+Cos(Winkel)*Fluegelradius;
FluegelEndPunkt.Y:=Drehpunkt.Y+Sin(Winkel)*Fluegelradius;
Hierbei wird der Winkel gegen den Uhrzeigersinn von der X-Achse aus gemessen.

[edit]Wie kann man denn so blöd sein... Danke, Nikolas[/edit]

Nikolas 28. Okt 2007 15:33

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Delphi-Quellcode:
FluegelEndPunkt.X:=Drehpunkt.X+Cos(Winkel);
FluegelEndPunkt.Y:=Drehpunkt.Y+Sin(Winkel);
Wobei Sinus und Cosinus auch noch mit dem Flügelradius multipliziert werden sollten, da man sonst nichts sieht.

Den Winkel zwischen zwei Flügeln findest du dann einfach per Winkel=2pi/Flügelanzahl raus, wenn dein Flügel nicht nur aus einem Strich sondern aus einem Dreieck bestehen soll, wäre so was eine Möglichkeit:
Delphi-Quellcode:
Winkel= 2pi/Flügelanzahl;
WinkelKlein = Winkel /3;
x=100;
y=100;
(pen.)moveto(x,y);
for i:=0 to Flügelanzahl do
 begin
 lineto(x+cos(winkel*i)*radius, y+sin(winkel*i)*radius);
 lineto(x+cos(winkel*i+winkelKlein)*radius, y+sin(winkel*i+winkelklein)*radius);
 lineto(x,y);
 end;
Ich habe den Code nicht getestet, er dürfte aber recht gut sein, hoffe ich mal.

spox 28. Okt 2007 15:44

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Danke schon mal für eure Antworten :-D
Ich weiß nur nicht, wo ich jetzt den Code von Nikolas einbauen soll... Soll ich dafür die ganze Muehle Prozedure überschreiben?
Und noch was: Winkel und WinkelKlein hab ich doch noch gar nicht definiert . . . Das kann doch gar nicht funktionieren, oder? :gruebel:

Nikolas 28. Okt 2007 15:51

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Zitat:

Ich weiß nur nicht, wo ich jetzt den Code von Nikolas einbauen soll... Soll ich dafür die ganze Muehle Prozedure überschreiben?
Und noch was: Winkel und WinkelKlein hab ich doch noch gar nicht definiert . . . Das kann doch gar nicht funktionieren, oder?
Der soll dan die Stelle, an der du die Flügel zeichnest. Noch mehr Hilfe solltest du eigentlich nicht brauchen. Nimm dir doch einfach mal einen Taschenrechner, ein geodreieck und einen Bleistift und führe den Code einfach aus. Dann wirst du ihn sicher verstehen.
Und die zweite Frage ist nicht wirklich ernst gemeint, oder?

Delphi-Quellcode:
Winkelstart=t*Omega;
Winkel = 2pi/Anzahl;
WinkelAkt= Winkelstart;
for i:=0 to Anzahl do
 begin
 lineto(x+cos(WinkelAkt)*radius, y+sin(WinkelAkt)*radius);
 lineto(x+cos(WinkelAkt+winkelKlein)*radius, y+sin(WinkelAkt+winkelklein)*radius);
 lineto(x,y);
 WinkelAkt += Winkel;
 end;
Wenn du jetzt t und Omega gescheit setzt (z.B. in einem Timer) könntest du die Windmühle sogar zum rotieren bringen :)

spox 28. Okt 2007 16:07

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Das wäre mein nächster Schritt :-D
Doch zunächst muss ich erstmal die Windräder hinkriegen. Und es will einfach nicht... :? Ich habe Apollonius Tipp befolgt, da meine Flügel keine Dreiecke, sondern einfach nur Striche sein sollen. Mein Programmcode sieht jetzt wie folgt aus:
Delphi-Quellcode:
unit muehleU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

const
 pi=3.1415;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure Muehle(anzahl,hoehe,x,y:integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 Muehle (4,150,50,50);
end;

procedure TForm1.Muehle (anzahl,hoehe,x,y:integer);
var flange,nr,bm,x2,y2, FluegelEndPunktX, FluegelEndPunktY:integer;
begin
 with Image1.Canvas do
  begin
   moveTo (x,y);
   rectangle (x,y,x+round(hoehe/5),hoehe);
   moveTo (x+(round(hoehe/5)DIV 2),y+10);
   x2:= x+(round(hoehe/5)DIV 2);
   y2:= y+10;
   flange:= hoehe DIV 2 ;
   bm:= round((2*pi) / anzahl);
   for nr:= 1 to anzahl do
   begin
   FluegelEndPunktX:=(hoehe DIV 10)+round(Cos(bm*nr));
   FluegelEndPunktY:=60+round(Sin(bm*nr));
   //lineTo (round(flange*cos(bm*nr)+(hoehe DIV 10)),round(-flange*sin(bm*nr)+60));
   lineTo (FluegelEndPunktX,FluegelEndPunktY);
   moveTo (x2,y2);
   end;
  end;
end;

end.

Nikolas 28. Okt 2007 16:11

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Und warum befolgst du nicht mal meinen Tipp?

Greif dir einen taschenrechner und gib doch mal das hier ein:

> FluegelEndPunktX:=(hoehe DIV 10)+round(Cos(bm*nr));

Was kommt da für ein Wert raus? Ist dieser Wert sinnvoll?

oldmax 29. Okt 2007 12:13

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Hi
Es ist relativ einfach, Windmühlenflügel zu programmieren. Überlegen wir, was notwendig ist:
Ein Mittelpunkt, dazu eignet sich ein TPoint. Dieser Variablentyp beinhaltet einen x und einen y Wert.
Z.B.
Delphi-Quellcode:
Nabe           : TPoint (Global )

Delphi-Quellcode:
Nabe.x:=256; // Beispiel, so initialisierst du deinen Mittelpunkt im FormCreate
Nabe.y:=55;
Zwei weitere Variablen machen Sinn

Delphi-Quellcode:
Gradzahl     : Real;   (Global) // veränderbare Winkelvariable für die Bewegung
AnzFluegel : Integer; (Global) // falls eine veränderbare Flügelzahl erwünscht....
Um eine Linie zu zeichnen benötigen wir nun einen Anfangspunkt und einen Endpunkt.
Also, Anfang ist Mitte, Endpunkt ist Flügellänge und Winkel von Mitte. Daraus machen wir eine Funktion, in der wir diese Werte als Parameter übergeben und einen TPoint-Wert erhalten:
Delphi-Quellcode:
Function TMyForm.Endpunkt( Radius: Integer; Winkel: Real; Zentrum : TPoint):TPoint;
Var xypunkt : TPoint;
Begin
   xypunkt.x:=Trunc(Cos(DegToRad(Winkel))*(-Radius))+Zentrum.x;
   xypunkt.Y:=Trunc(Sin(DegToRad(Winkel))*(-Radius))+Zentrum.Y;
   Result:= xypunkt;
End;
Nun die Zeichnung der Linie, am besten eine Procedur mit den Parametern Anfangspunk, Endpunkt und Farbe. Die Farbe brauchst du, um die alte Zeichnung wieder zu löschen. Nehmen wir an, du zeichnest auf einem grünen Untergrund. Eine Rote Linie ist sichtbar, eine grüne nicht...
Also
Delphi-Quellcode:
Procedure TMyForm.ShowFluegel(Anfang,Ende: Tpoint; Farbe : TColor);
Begin
   MyForm.Canvas.Pen:Color:=Farbe;
   MyForm.Canvas.Moveto(Anfang.x, Anfang.Y);
   MyForm.Canvas.Lineto(Ende.x, Ende.Y);
End;
Eigentlich lassen sich jetzt schon die Programmzeilen testen, wenn ich z.B. über ein Button erst mal einen Endpunkt errechne und dann anschließend die Anzeige aufrufe. Du willst aber die Flügellänge und die Anzahl der Flügel selbst bestimmen. Nun gut, 2 Editfelder mit den Werten und nun geht es los.

In die Ereignisroutine deines Tasters setzt du erst mal folgenden Code:

Delphi-Quellcode:
Procedure TMyForm.MyButtonClick(Sender:Tobject);
Var i                   :   Integer;
      Sektorwinkel : Real;
      Kreispunkt    : Tpoint;
Begin
    AnzFluegel :=StrToInt(Ed_Fluegel.Text); //Editfeld mit Namen ED_Fluegel // globale Variable setzen
    For i:=1 to AnzFluegel do // jeden einzelnen Flügel berechnen und darstellen
    Begin
        SektorWinkel:=360/Anzfluegel *i; // Winkel der einzelnen Flügel berechnen
        Sektorwinkel:=Sektorwinkel+GradZahl; // Irgendwann soll sich das Windrad ja drehen
        If SektorWinkel > 360 then Sektorwinkel:=Sektorwinkel-360; // wir bleiben bei 360 ° Kreis
        Kreispunkt :=EndPunkt(StrToInt(Ed_Fluegellaenge.Text),Sektorwinkel,Nabe); // separater Aufruf schafft Durchblick
        ShowFluegel(Nabe, Kreispunkt, ClGreen); // erst mal unsichtbar......
    End; // I-Schleife
    Gradzahl:=Gradzahl+1;                   // Gradzahl erhöhen, >1 wird die Drehung schneller
    If GradZahl>360 then GradZahl:=1; // auf 360° begrenzen
    For i:=1 to AnzFluegel do               // und jeden einzelnen Flügel berechnen und darstellen
    Begin
        SektorWinkel:=360/Anzfluegel *i; // Winkel der einzelnen Flügel berechnen
        Sektorwinkel:=Sektorwinkel+GradZahl; // Irgendwann soll sich das Windrad ja drehen
        If SektorWinkel > 360 then Sektorwinkel:=Sektorwinkel-360; // wir bleiben bei 360 ° Kreis
        Kreispunkt :=EndPunkt(StrToInt(Ed_Fluegellaenge.Text),Sektorwinkel,Nabe);
       ShowFluegel(Nabe, Kreispunkt, ClRed); // jetzt sichtbar......
    End; // I-Schleife

End;
Nun kannst du mit Tastendrücken schrittweise prüfen, ob alles klappt. Ist es nach deinem Geschmack geraten, kannst du an die Automatisierung gehen. Nimm einen Timer und kopiere dein Button-Ereignisprogramm mit den Variablen hinein. Die Zuweisung der AnzFluegel-Variable löschst du im Timer Ereignis und im Button-Ereignis löscht du alles außer der Zuweisung der AnzFluegel-Variable.
Feddisch........

Noch mal eine kurze Bemerkung zu fogenden Zeilen

Delphi-Quellcode:
Kreispunkt :=EndPunkt(StrToInt(Ed_Fluegellaenge.Text),Sektorwinkel,Nabe); // separater Aufruf schafft Durchblick
ShowFluegel(Nabe, Kreispunkt, ClGreen); // erst mal unsichtbar......
Das geht auch ....
Delphi-Quellcode:
ShowFluegel(Nabe, EndPunkt(StrToInt(Ed_Fluegellaenge.Text), Sektorwinkel, Nabe), ClGreen);
Kreispunkt wird mit dem Funktionsaufruf ersetzt und erspart die Variable „Kreispunkt“
Ist aber schlecht zu Kommentieren und für Anfänger nicht
Gruß oldmax

shmia 29. Okt 2007 12:51

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
Ich würde dringend empfehlen, folgende Funktionen zu verwenden:
Drehung und Verschiebung im 2D Raum
Damit wird das Zeichnen eines Flügels stark vereinfacht.
1.) ein Flügel ist ein Polygon und wird mit Canvas.Polygon(Points: array of TPoint) gezeichnet
2.) die Punkte des Flügel werden auf Karopapier so gezeichnet, dass der Drehpunkt auf (0,0) liegt
3.) jetzt braucht es 2 Operationen, um einen Flügel in beliebiger Richtung und Position zu zeichen
4.) mit Rotate2Darray() werden alle Punkte um den vorgegebenen Winkel gedreht
5.) mit Translate2Darray() wird der Drehpunkt des Flügels (der ja noch immer bei (0,0) liegt)
in den Drehpunkt der Windmühle verschoben

Diese Vorgehensweise hat viele Vorteile:
* wiederverwendbar (taugt auch für Games, Spielkarten, ...)
* flexibel (das Flügelprofil in Schritt 2.) kann völlig frei gestaltet werden)
* sauber gekapselt (die ganze Mathematik liegt in Rotate2Darray() & Translate2Darray())
* mit etwas Zusatzaufwand kann man die ganze Zeichnung auch zoomen

spox 11. Nov 2007 15:54

Re: Windmühle, bei der die Flügelanzahl variabel ist
 
So ... sry, dass ich erst jetzt antworte, aber mein Internet hat gestreikt :pale:

Ich habe es jetzt geschafft, die Flügel zu zeichnen, sodass sie in dem richtigen Winkel zueinander stehen. Doch wie könnte es anders sein: Die Drehung scheint noch nicht zu klappen... Die Idee zu der Drehung die ich hatte: die Mühleprozedur in eine TimerRoutine und dann mit Weiß übermalen. Danach den Winkel verändern und mit Schwarz malen. Danach wieder mit weiß, usw.

Doch wie verändere ich den Winkel? Ich habe das Bogenmaß 2 pi genommen. Jetzt wollte ich einfach in der zeichenRoutine um ein Grad addieren. Doch es will nicht:

Delphi-Quellcode:
unit muehleU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

const
 pi=3.1415;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    Edit1: TEdit;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Timer1: TTimer;
    Button6: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Muehle(anzahl,hoehe,x,y:integer);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  v:integer;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var z:integer;
begin
 z:= StrToInt(Edit1.Text);
 Muehle (z,150,50,50);
end;

procedure TForm1.Muehle (anzahl,hoehe,x,y:integer);
var flange,nr,x2,y2,FluegelEndeX,FluegelEndeY:integer;
begin
 with Image1.Canvas do
  begin
   moveTo (x,y);
   rectangle (x,y,x+round(hoehe/5),hoehe);
   moveTo (x+(round(hoehe/5)DIV 2),y+10);
   x2:= x+(round(hoehe/5)DIV 2);
   y2:= y+10;
   flange:= hoehe DIV 2 ;
   for nr:= 1 to anzahl do
   begin
    FluegelEndeX:= x2+round(flange*cos(nr*(2*pi+v)/anzahl));
    FluegelEndeY:= y2+round(flange*sin(nr*(2*pi+v)/anzahl));
    lineTo (FluegelEndeX,FluegelEndeY);
    moveTo (x2,y2);
   end;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Muehle (2,150,50,50);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 Muehle (8,150,50,50);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 Muehle (20,150,50,50);
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
 Muehle (150,150,50,50);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 Image1.Canvas.Pen.Color:= clBlack;
 Muehle (8,150,50,50);
 Image1.Canvas.Pen.Color:= clWhite;
 Muehle (8,150,50,50);
 Image1.Canvas.Pen.Color:= clBlack;
 Muehle (8,150,50,50);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
Timer1.Enabled:= true;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
v:= 0
end;

end.
Ich hoffe ihr wollt mir noch helfen. Schließlich hab ich mich ja nicht gemeldet :pale:


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:40 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz