Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Winkel zwischen zwei Punkten?! (https://www.delphipraxis.net/139411-winkel-zwischen-zwei-punkten.html)

Vasco da Gama 28. Aug 2009 10:56


Winkel zwischen zwei Punkten?!
 
Hallo, nach viel googlen finde ich einfach nicht, wonach ich suche. Selbst kann ich es nicht beantworten, da ich Winkelfunktionen(sin, cos, tan, etc.) in der Schule noch nicht gelernt habe.

Ich habe einen TPoint, nennen wir ihn P1.
Dann klicke ich mit der Maus:
Delphi-Quellcode:
begin
...
  GetCursorPos(p2);
  p2 := ScreenToClient(p2);
  SetDir(round(Tan((P1.Y - P2.Y) / (P1.X - P2.X))));
...
end;
SetDir ist folgendes:
Delphi-Quellcode:
procedure TEinheit.SetDir(ADirection: Integer);
var
  w:integer;
begin
  //Reset the speed variables
  FYSpeed := 0;
  FXSpeed := 0;


  w := ADirection;

  //Set the X and the Y speed
  FXSpeed := round(cos(PI/180*w)*Speed);

  FYSpeed := round(sin(PI/180*w)*Speed);

  AnimLoop := true;
  AnimActive := true;
end;
Vielleicht inzwischen erraten, es ist ein Andorra 2D Projekt ;)
die DoMove procedure von TEinheit ist folgende:
Delphi-Quellcode:
procedure TEinheit.DoMove(TimeGap: Double);
begin
inherited DoMove(TimeGap);
    X := X + FXSpeed * TimeGap;
    Y := Y + FYSpeed * TimeGap;
end;

Tja, egal wohin ich klicke, er läuft immer nach rechts(die Animation soll ja nach rechts laufen, aber der Sprite soll dahin laufen, wohin ich klicke...)

Info: Da ich mich ja mit Winkelfunktionen nicht auskenne, habe ich mir die Sinus Cosinus und ArcTangens dinger aus Demos rausgeschnappt....

Uwe Raabe 28. Aug 2009 11:18

Re: Winkel zwischen zwei Punkten?!
 
Delphi-Quellcode:
...
uses
  Math;
...
  SetDir(round(ArcTan2(P1.Y - P2.Y, P1.X - P2.X))));
...

Medium 28. Aug 2009 11:18

Re: Winkel zwischen zwei Punkten?!
 
Einen Winkel zwischen 2 Punkten gibt es nicht. Was du hier meinst ist der Winkel einer Geraden gegeben durch 2 Punkte zu einer Koordinatenachse. Allerdings hat das ganze ein Problem: Der Winkel wird immer positiv und zwischen 0..PI/2 liegen, was heisst dass du quasi immer nur nach "oben rechts" guckst. Die Quadrantenbestimmung kann man zwar machen, ist aber wieder zusätzlicher Rechenaufwand.* Letztlich sind triginometrische Ansätze fast immer langsamer, ungenauer und "mehr Code" als die Alternative: Du ersparst ne Menge Ärger wenn du das Vektoriell an gehst.
*Edit: ATan2 macht diese Unterscheidung, dennoch bist du mit ein wenig Rumvektorn am Ende deutlich besser dran.

Sagen wir mal P0=(x0, y0) ist wo dein Sprite gerade ist, und P1=(x1, y1) ist der Punkt auf den geklickt wurde. Dann ist V'=(x1-x0, y1-y0) der Vektor der von P0 aus auf P1 zeigt. (P0+V'=P1)
Um von P0 aus nun schrittweise (also animiert) zu P1 zu gelangen, musst nun immer nur Bruchstücke von V' zu P0 addieren: P0+t*V'=P', wobei t|[0..1]. Bei t=0 ist P'=P0, und bei t=1 ist P'=P1.

jfheins 28. Aug 2009 11:22

Re: Winkel zwischen zwei Punkten?!
 
Also wenn deine Einheit bei X, Y ist, und an Position p2.X, p2,Y geklickt wurde ... geht dann nicht sowas:
Delphi-Quellcode:
p2.X := p2.X - X;
p2.Y := p2.Y - Y;

FXSpeed := p2.X / sqrt(p2.X * p2.X + p2.Y * p2.Y);
FYSpeed := p2.Y / sqrt(p2.X * p2.X + p2.Y * p2.Y);
Wozu die umrechnung in Polarkoordinaten, um die dann wieder in kartesische umzurechnen?

Luckie 28. Aug 2009 11:49

Re: Winkel zwischen zwei Punkten?!
 
"Winkel zwischen zwei Punkten" Den Unsinn habe ich doch jetzt neulich erst irgendwo gelesen. Ich glaube das war irgendwo im DF. Keine Ahnung, ob dir das hilft.

jfheins 28. Aug 2009 11:54

Re: Winkel zwischen zwei Punkten?!
 
Meinst du das da: http://www.delphi-forum.de/viewtopic.php?t=94070 :?:

Luckie 28. Aug 2009 12:04

Re: Winkel zwischen zwei Punkten?!
 
Jupp, das wars. Waren doch keine zwei Punkte, sondern ein Kreis.

Vasco da Gama 28. Aug 2009 12:26

Re: Winkel zwischen zwei Punkten?!
 
Zitat:

Zitat von jfheins
Also wenn deine Einheit bei X, Y ist, und an Position p2.X, p2,Y geklickt wurde ... geht dann nicht sowas:
Delphi-Quellcode:
p2.X := p2.X - X;
p2.Y := p2.Y - Y;

FXSpeed := p2.X / sqrt(p2.X * p2.X + p2.Y * p2.Y);
FYSpeed := p2.Y / sqrt(p2.X * p2.X + p2.Y * p2.Y);
Wozu die umrechnung in Polarkoordinaten, um die dann wieder in kartesische umzurechnen?

Vielen Dank, mit dem Code klappts perfekt :thumb:


Zitat:

Zitat von Luckie
"Winkel zwischen zwei Punkten" Den Unsinn...

Tja, tut mir Leid, für den Unsinn aber ich wusste nicht wie ich es beschreiben sollte.

mfG :dp:

Medium 28. Aug 2009 13:42

Re: Winkel zwischen zwei Punkten?!
 
Zitat:

Zitat von Vasco da Gama
Vielen Dank, mit dem Code klappts perfekt :thumb:

Das ist übrigends fast das selbe, nur in Code gegossen, was ich beschrieben hab - nur damit du den Zusammenhang erkennst. Hier wird nu lediglich mein V' auf eine Länge von 1 skaliert (=normiert), wobei dann, um es mathematisch auszudrücken, in der Formel von oben P0+t*V'=P' das t im Intervall [0..dist(P0, P1)] statt [0..1] liegt.
Eine Richtung normiert anzugeben ist üblicher, soll die Richtung auch gleich noch die Geschwindigkeit enthalten ist dies die Länge dieses Vektors. Ich hatte imch oben für die ungewöhnlichere Variante entschieden, da t dann immer in 0..1 liegt, und man über die Schrittweite von t die Geschwindigkeit ohne viel Rechnerei nachträglich festlegen/variieren konnte, und vor allem nicht dank Rundungsfehlern evtl. P1 verfehlt. Aber dat sind nu schon Feiheiten =)

Vasco da Gama 3. Sep 2009 10:51

Re: Winkel zwischen zwei Punkten?!
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok. jetzt hab ich eine weitere Frage, die durch das Bild im Anhang verdeutlicht werden sollte.

Dort, wo sich die Linien schneiden ist der Nullpunkt. dort ist der Punkt X
Jetzt will ich, jenachdem wo der zweite Punkt ist, etwas anderes machen. Je nachdem, welcher linie der Punkt am nächsten ist.
Kann man das lösen ? Bitte eine möglichts einfache Erklärung oder Code, damit ich es auch verstehe

mfG und ich hoffe ich nerve nicht zu sehr :pale:
VdG

jfheins 3. Sep 2009 12:04

Re: Winkel zwischen zwei Punkten?!
 
ist ähnlich simpel - Punkt in Polarkoordinaten umrechnen (Winkel zwischen 0 und 2PI).
Zum Winkel dann (2*PI/16) addieren, modulo 2 PI nehmen und dann mit 8/(2*PI) multiplizieren, Dezimalstellen abschneiden und fertig ;)

Den Winkel bekommst du mit der Funktion arctan2() aus der Math-Unit.

Um zu verstehen, was passiert kannst du dir das mal auf einem Blatt Papier verständlich machen - es wird ja im Grunde nur der Winkel genommen und in eine Richtung überführt.
Wenn du es immernoch nicht vestehst, mach mal eine Tabelle, welcher Winkel welche Zahl bekommen soll. Also z.B.

0° =>0
22°=>0
23°=>1
45°=>1
67°=>1
68°=>2
...
337°=>7
338°=>0
359°=>0

Also ist die Lösung, einen Winkel draufzuaddieren, das Ergebnis passend zu teilen und dann die Kommastellen abzuschneiden (Übergang kontinuierlich=>diskret)

Vasco da Gama 3. Sep 2009 12:41

Re: Winkel zwischen zwei Punkten?!
 
Danke,hier am Laptop hab ich kein Delphi. Werds dann später testen und Rückmeldung geben :cheers: :coder:

Vasco da Gama 3. Sep 2009 17:50

Re: Winkel zwischen zwei Punkten?!
 
Hi, folgenden Code hab ich mal zum Testen eingegeben.
Delphi-Quellcode:
Zahl := arctan2(Aim.Y, Aim.X);
  Zahl := Zahl + (2*PI/16);
  Zahl := Zahl mod 2*Pi;
  Zahl := Zahl * (8/(2*PI));
  Showmessage(IntToStr(round(Zahl)));
Da erhalte ich die meldung:
Zitat:

[DCC Fehler] SpielForm.pas(540): E2015 Operator ist auf diesen Operandentyp nicht anwendbar
in der Zeile mit mod, da mod ja nur für Integer gilt. Gibt es mod auch für Gleitkommazahlen(Extended)? Oder hab ich deine Antwort ganz falsch verstanden?

Danke nochmal, mfG

jfheins 3. Sep 2009 17:53

Re: Winkel zwischen zwei Punkten?!
 
nein, haste schon richtig verstanden.

Wenn es in der Math-Unit keine Mod-Funktion für Gleitkommazahlen gibt, reicht auch ein

Delphi-Quellcode:
if zahl > 2*Pi then zahl := zahl - 2*Pi;
if zahl < 0 then zahl := zahl + 2*Pi;
Das erledigt dann auch gleich die "zwischen 0 und 2 Pi"-Sache (arctan2() liefert evtl. auch negative Werte zurück)

Vasco da Gama 3. Sep 2009 18:00

Re: Winkel zwischen zwei Punkten?!
 
Danke, aber jetzt bekomme ich mit:
Delphi-Quellcode:
Zahl := arctan2(Aim.Y, Aim.X);
  Zahl := Zahl + (2*PI/16);
  //Zahl := Zahl mod 2*Pi;
  if zahl > 2*Pi then zahl := zahl - 2*Pi;
  if zahl < 0 then zahl := zahl + 2*Pi;
  Zahl := Zahl * 8/(2*PI);
  Showmessage(IntToStr(round(Zahl)));
Nur entweder eins oder zwei zurückgegeben. Da muss wohl was falschgelaufen sein...?

Wolfgang Mix 3. Sep 2009 18:46

Re: Winkel zwischen zwei Punkten?!
 
jfheins schrieb:

Delphi-Quellcode:
if zahl > 2*Pi then zahl := zahl - 2*Pi;
if zahl < 0 then zahl := zahl + 2*Pi;
Der Tangens hat eine Periodizität von 180 Grad (oder pi):
Versuche 'mal

Delphi-Quellcode:
if zahl > Pi then zahl := zahl - Pi;
if zahl < 0 then zahl := zahl + Pi;
Gruß

Wolfgang

jfheins 3. Sep 2009 19:05

Re: Winkel zwischen zwei Punkten?!
 
Möööp :mrgreen:

Der Tangens interessiert gar nicht, es wird einmal der arkustangens berechnet und dann ist das nur noch ein Winkel, und der geht schon einmal ganz um den Kreis - also im Intervall 0..2PI oder 0..360° ;)

Also ich weis nicht, was du machst, aber mein Testcode geht:
Code:
private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            label5.Text = string.Format("X: {0}\t Y: {1}", e.X, e.Y);

            var x = e.X - 150;
            var y = e.Y - 150;

            var Winkel = Math.Atan2(y, x);

            label1.Text = (Winkel * 180 / Math.PI).ToString() + " °";

            Winkel = Winkel + (2 * Math.PI / 16);

            label2.Text = (Winkel * 180 / Math.PI).ToString() + " °";

            if (Winkel > 2 * Math.PI)
                Winkel = Winkel - 2 * Math.PI;
            if (Winkel < 0)
                Winkel = Winkel + 2 * Math.PI;

            label3.Text = (Winkel * 180 / Math.PI).ToString() + " °";

            var Linie = Math.Truncate(Winkel * 8 / (2 * Math.PI));

            label4.Text = Linie.ToString();
        }
Vergisst du vll. vorher die Koordinaten des Ursprungs abzuziehen?

Wolfgang Mix 3. Sep 2009 20:28

Re: Winkel zwischen zwei Punkten?!
 
@jfheins

Zitat:

if (Winkel > Math.PI)
Winkel = Winkel - Math.PI;
if (Winkel < 0)
Winkel = Winkel + Math.PI;
Das müßte auch in C# klappen.

Ansonsten teile ich auch deine Meinung mit den Ursprungskoordinaten.


Probiere 'mal bitte

Gruß

Wolfgang

jfheins 3. Sep 2009 20:47

Re: Winkel zwischen zwei Punkten?!
 
Zitat:

Zitat von Wolfgang Mix
Probiere 'mal bitte

Bringt - wie erwartet - falsche Ergebnisse ;)

Durch die Beschränkung auf den Bereich 0..180° wird nur noch ein Halbkreis abgedeckt, statt der ganze Kreis. Das Ergebnis ist, dass rechts 0 kommt, dann nach unten rechts die 1 dann nach unten die 2 und nach unten links die 3. Anstatt danach aber mit 4-7 weiter zugehen, fängt es wieder bei 0 an. Ist ja auch logisch, wenn der obere Halbkreis durch das if winkel > pi then einkel := winkel - pi auf den unteren Halbkreis abgebildet wird ;)

Wolfgang Mix 3. Sep 2009 21:05

Re: Winkel zwischen zwei Punkten?!
 
Ok, danke für den Test.

Irren ist menschlich, sprach der Igel und stieg von der Drahtbürste ;-)

Gruß

Wolfgang

jfheins 3. Sep 2009 21:27

Re: Winkel zwischen zwei Punkten?!
 
Kein Problem, lieber ein falscher Einspruch + Test als ein unentdeckter Fehler ;)


Zitat:

Zitat von Wolfgang Mix
Irren ist menschlich, sprach der Igel und stieg von der Drahtbürste ;-)

:lol:

Vasco da Gama 4. Sep 2009 08:00

Re: Winkel zwischen zwei Punkten?!
 
Danke, mit dem Abzug der Ursprungskoordinaten klappts wunderbar, ihr seid die Größten! :dp:


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:50 Uhr.

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