Laden...

Mathematisches Problem: Koordinaten

Erstellt von Jack_AI vor 16 Jahren Letzter Beitrag vor 16 Jahren 2.255 Views
J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren
Mathematisches Problem: Koordinaten

Hallo!

Ich möchte in C# ein Objekt1 auf Objekt2 zugehen lassen. Gegeben sind also die Koordinaten von Objekt1 und Objekt2 und die Geschwindigkeit von Objekt1. Dazu suche ich eine Formel, mit der ich die Position von Objekt1 zum Zeitpunkt t herausfinden kann.

Mein Ansatz wäre:

cos a = (X1 * X2 + Y1 * Y2) / (sqrt(X1² + Y1²) * sqrt(X2² + Y2²))
X1 = X1 - X1 * t * v * cos a
Y1 = Y1 - Y1 * t * v * cos a

bzw. in C#-Code:


double CosWinkel = (PosX * ZielX + PosY * ZielY) / 
  (Math.Sqrt(Math.Pow(PosX, 2) + Math.Pow(PosY, 2)) * 
  Math.Sqrt(Math.Pow(ZielX, 2) + Math.Pow(ZielY, 2)));
PosX = (PosX - PosX * ZeitpunktBewegung * Speed * CosWinkel);
PosY = (PosY - PosY * ZeitpunktBewegung * Speed * CosWinkel);

Allerdings haut das irgendwie nicht hin. Das Ergebnis ist, dass Objekt1 immer nach links oben fährt, unabhängig vom Ziel (was eigentlich durch das cos a verhindert werden soll). Ich habe versucht, die Formel durch Probieren herauszufinden, was aber an meinen geringen Physikkenntnissen gescheitert ist.

Wenn mir jemand hier helfen könnte, wäre das janz doll. Danke.

184 Beiträge seit 2005
vor 16 Jahren

Hab die Formel jetzt selber gar nicht untersucht -- aber ein häufiger Fehler ist, dass mit int werten gerechnet wird -- sind bei dir PosX, ZielX, PosY und ZielY alle vom Typ double?

Frohes Neues 🙂

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Frohes Neues 🙂

Dir auch! 🙂

Hab die Formel jetzt selber gar nicht untersucht -- aber ein häufiger Fehler ist, dass mit int werten gerechnet wird -- sind bei dir PosX, ZielX, PosY und ZielY alle vom Typ double?

Ja, sind alle double. Es stimmt: Zuvor habe ich int benutzt, was zu merkwürdigen Fehlern geführt hat.

O
17 Beiträge seit 2007
vor 16 Jahren

Stell erstmal den Richtungsvektor 0X2-0X1 auf.

Aus diesem Vektor holst du dir mit ArcTan den Winkel phi des Richtungsvektors.

Für deine zurückgelegte Wegstrecke: v*t (eh klar)

Die !Komponenten! der der Bewegung:

x=vtcos(phi)
y=vtsin(phi)

zu deinem 0X1 komponentenweise addiert erhälts du den Ortsvektor deines bewegten Punktes.

Hoffe ich konnte dir weiterhelfen bei diesem Dynamikbeispiel.

N
46 Beiträge seit 2007
vor 16 Jahren

Mein Ansatz wäre:

cos a = (X1 * X2 + Y1 * Y2) / (sqrt(X1² + Y1²) * sqrt(X2² + Y2²))
...

Ich hab keine Ahnung, wie Du auf diese Formel kommst und ob diese annaehrend korrekt sein kann. Fuer mich persoenlich muss grundsaetzlich ein Minus-Zeichen in einer Formel auftauchen, wenn aus Koordinatenpaaren ein Winkel berechnet werden soll.

Gruesse,

N1ls

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

@O5IRI5:

Danke für deinen ausführlichen Hinweis! Leider habe ich überhaupt keine Ahnung von Vektoren, sonst hätte ich selber versucht es mit Vektoren zu berechnen.

@N1ls:

Mein Ansatz wäre:

cos a = (X1 * X2 + Y1 * Y2) / (sqrt(X1² + Y1²) * sqrt(X2² + Y2²))
...

Ich hab keine Ahnung, wie Du auf diese Formel kommst und ob diese annaehrend korrekt sein kann. Fuer mich persoenlich muss grundsaetzlich ein Minus-Zeichen in einer Formel auftauchen, wenn aus Koordinatenpaaren ein Winkel berechnet werden soll.

Gruesse,

N1ls

Hallo N1ls,

die Formel habe ich von hier. Ich habe lediglich die Z-Dimension vernachlässigt.

Grüße,
Jack

O
17 Beiträge seit 2007
vor 16 Jahren

Leider habe ich überhaupt keine Ahnung von Vektoren, sonst hätte ich selber versucht es mit Vektoren zu berechnen.

Hast du implizit ja schon gemacht.

cos a = (X1 * X2 + Y1 * Y2) / (sqrt(X1² + Y1²) * sqrt(X2² + Y2²))

Mit dem Skalarprodukt kannst du Winkel berechnen, aber wenn ich das richtig interpretiere errechnest du den Winkel zwischen den beiden Punkten. Also der eine Vektor zeigt vom Ursprung auf Punkt O1 und der zweite vom Ursprung auf Punkt O2
dein Winkel ist der dazwischen.

630 Beiträge seit 2007
vor 16 Jahren

Liegt vieleicht eine verwechslung zwischen Gradmaß und Bogenmaß vor?

Gruss
tscherno

DISCLAIMER:
Ich weis granicht ob dass in diesem zusammenhang relevant ist da ich keien Ahnung von Mathe habe, will aber darauf hinweisen das die Math Methoden alle Winkel im Bogenmaß erwarten. Wenn ich also schwachsinn schreibe dann bitte ignorieren. 😉

To understand recursion you must first understand recursion

http://www.ilja-neumann.com
C# Gruppe bei last.fm

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

      double CosWinkel = (PosX * ZielX + PosY * ZielY) / 
        (Math.Sqrt(Math.Pow(PosX, 2) + Math.Pow(PosY, 2)) * 
        Math.Sqrt(Math.Pow(ZielX, 2) + Math.Pow(ZielY, 2)));
      double Winkel = Math.Acos(CosWinkel);

Ich habe mit mal das Ergebnis von "Winkel" ausgeben lassen. Das scheint irgendwie nicht zu stimmen. Wenn das Ziel die Koordinaten 1/1 hat und Position die Koordinaten 400/400, muss logischerweise der Winkel 45° sein, bzw. 315°. Ich bekomme aber als Ergebnis 1,49 * 10 hoch -8! (Als Bogenmaß interpretiert wäre der Winkel immerhin noch 8,5 * 10 hoch -7)

edit:
Oh, wow! Ich glaube, ich hab's jetzt! Ein Freund hat mich auf die Formel


      double TanWinkel = (PosY - ZielY) / (PosX - ZielX);
      double Winkel = Math.Atan(TanWinkel);

aufmerksam gemacht. Und siehe da: Wenn ich das Ergebnis als Bogenmaß interpretiere, bekomme ich einen Winkel von 45 Grad raus!

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Mit dieser Formel


      PosX = PosX - (ZeitpunktBewegung * Speed * CosWinkel);
      PosY = PosY - (ZeitpunktBewegung * Speed * SinWinkel);

habe ich das Problem, dass mein Objekt zuerst wendet, bevor es das Ziel ansteuert, und dabei an Geschwindigkeit zunimmt.

Mein Programm (.exe-Datei) (Position ist 400/400, Ziel ist 600/1)

N
46 Beiträge seit 2007
vor 16 Jahren

Oh, wow! Ich glaube, ich hab's jetzt! Ein Freund hat mich auf die Formel

  
      double TanWinkel = (PosY - ZielY) / (PosX - ZielX);  
      double Winkel = Math.Atan(TanWinkel);  
  

aufmerksam gemacht. Und siehe da: Wenn ich das Ergebnis als Bogenmaß interpretiere, bekomme ich einen Winkel von 45 Grad raus!

Ahh 🙂 Da ist das von mir vermisste Minus-Zeichen 🙂

Du bist definitiv auf dem richtigen Weg, aber Vorsicht! Sobald beide Objekte die gleiche X-Koordinate haben, laeufst Du in eine Exception. Den Sonderfall musst Du behandeln.

J
1.114 Beiträge seit 2007
vor 16 Jahren

Stell erstmal den Richtungsvektor 0X2-0X1 auf.

Aus diesem Vektor holst du dir mit ArcTan den Winkel phi des Richtungsvektors.

Für deine zurückgelegte Wegstrecke: v*t (eh klar)

Die !Komponenten! der der Bewegung:

x=vtcos(phi)
y=vtsin(phi)

zu deinem 0X1 komponentenweise addiert erhälts du den Ortsvektor deines bewegten Punktes.

Hoffe ich konnte dir weiterhelfen bei diesem Dynamikbeispiel.

Aber unbedingt darauf achten, dass dein Vektor v normiert ist!

O
17 Beiträge seit 2007
vor 16 Jahren

Aber unbedingt darauf achten, dass dein Vektor v normiert ist!

Wie kommst du darauf?

LG
Harry

J
1.114 Beiträge seit 2007
vor 16 Jahren

Wie kommst du darauf?

Weil du, um die r(x,y) Koordinate zu rechnen korrekterweise hingehst und
x(t)=vtcos(phi)
ausrechnest (y analog).

Wenn v nicht normiert ist, so ist t nicht deine einzige Laufvariable, weil die Norm von v abhängig ist von den Start- und Zielkoordinaten.

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Hallo.

Ich habe jetzt einen neuen Ansatz, nachdem Cosinus und Sinus zu merkwürdigem Verhalten geführt haben:

PosX = StartPosX + StartPosX * Speed * Zeit;
PosY = StartPosX + StartPosY * Speed * Zeit * Steigung;

Doch das führt auch zu einem merkwürdigen Problem. Das Objekt steuert das Ziel richtig an, aber nach ca. 3/4 der Strecke nimmt das Objekt zufällige Positionen an. Es "tanzt wild herum", sozusagen. Ich kann mir dieses Verhalten nicht erklären.

Und noch eine dumme Frage:


      double Steigung;

      if (DeltaX() != 0)
        Steigung = DeltaY() / DeltaX();
      else
        ???

Wie behandle ich die Steigung, wenn DeltaX gleich Null ist?

Danke,
Jack

J
1.114 Beiträge seit 2007
vor 16 Jahren

nachdem Cosinus und Sinus zu merkwürdigem Verhalten geführt haben

Inwiefern?

Die Sache mit deiner Steigung klappt so nicht, da du die Geschwindigkeit nur abhängig von der x-Richtung machst. Je grösser die Steigung, desto schneller wird sich also dein Objekt bewegen... Lediglich die x-Geschw. bleibt konstant. Und das sollte auch deine Frage beantworten, wenn vx=0 wird... Dann geht die Steigung ins Unendliche.

Bleib also lieber bei der trigonometrischen Lösung.

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Oh, wow. Ich habe es endlich hinbekommen! Ich behaupte einfach mal, dass ich das Problem jetzt gelöst habe, lasse mich aber gerne eines Besseren belehren. Wenn meine Lösung jetzt stimmt, schreibe ich nachträglich noch einen (längeren?) Beitrag, für all diejenigen, die mit den gleichen Problemen zu kämpfen haben werden, und gehe dabei auf meine gemachten Fehler ein.

Die entscheidende Stelle sieht jetzt so aus:


      double NextPosX;
      double NextPosY;

      // Formeln müssen für größeres / kleineres Ziel angepasst werden

      if (PosX < ZielX)
        NextPosX = StartPosX + StartPosX * Speed * Zeit * Math.Cos(WertWinkel);
      else 
        NextPosX = StartPosX - StartPosX * Speed * Zeit * Math.Cos(WertWinkel);

      if (PosY < ZielY)
        NextPosY = StartPosY + StartPosY * Speed * Zeit * Math.Sin(WertWinkel);
      else
        NextPosY = StartPosY - StartPosY * Speed * Zeit * Math.Sin(WertWinkel);

      // wenn das Ziel zwischen der aktuellen und der nächsten Position liegt
      if ((ZielX >= PosX && ZielX <= NextPosX) || (ZielY >= PosY && ZielY <= NextPosY) ||
        (ZielX <= PosX && ZielX > NextPosX) || (ZielY <= PosY && ZielY > NextPosY))
      {
        ZielWurdeErreicht();
        return true;
      }

      PosX = NextPosX;
      PosY = NextPosY;

      return false;

Was ich allerdings noch nicht behoben habe, ist, wie man vorgeht, wenn DeltaX 0 wird:


      if (DeltaX() != 0)
        Steigung = DeltaY() / DeltaX();
      else
        Steigung = ???

Wenn mir hier noch jemand auf die Sprünge helfen könnte, wäre das sehr nett.
Jack

J
1.114 Beiträge seit 2007
vor 16 Jahren

Ich versteh nicht recht... Die Steigung geht doch gar nicht mehr in deine Berechnung ein.

Jedenfalls ist y/x ein Grenzwertproblem, für x->0
Du musst also den Limes bilden
lim y/x
x->0+

0+ heisst hier dass sich x aus dem Positiven der 0 nähert. Negative x-Werte hast du ja in deinem Bsp. denk ich nicht, sonst musst du das auch berücksichtigen.

Dein y (also eigentlich dein DeltaY... habs hier nur verkürzt darstellen wollen), kann aber sehr wohl positiv oder negativ sein (die Gerade ist also steigend oder abfallend). Du brauchst hier also eine Fallunterscheidung. Was Positives geteilt durch eine "positive" Null macht +Unendlich. Was Negatives durch 0+ macht folglich -Unendlich.

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Ich versteh nicht recht... Die Steigung geht doch gar nicht mehr in deine Berechnung ein.

Du hast recht. Daran habe ich gar nicht mehr gedacht. Richtig lösen konnte ich das Problem nicht. Dafür müsste ich erst wieder meine Mathekenntnisse auffrischen. Schon dieses vermeintlich einfache Problem hat jetzt vorerst genug mathematisches und physikalisches Wissen von mir abverlangt.

Die Lösung:

Ich konnte das Ganze nun entgültig lösen. Die Formel war übrigens nicht ganz richtig. Richtig ist die Formel so (im Vergleich zur vorherigen falschen Formel nähme die Geschwindigkeit konstant zu):


      if (PosX < ZielX)
        NextPosX = StartPosX + Speed * Zeit * CosWinkel;
      else
        NextPosX = StartPosX - Speed * Zeit * CosWinkel;

      if (PosY < ZielY)
        NextPosY = StartPosY + Speed * Zeit * SinWinkel;
      else
        NextPosY = StartPosY - Speed * Zeit * SinWinkel;

Ich versuche hier noch mal grob meine Gedanken zu dokumentieren, damit andere Anfänger und Fortgeschrittene mit dem selben Problem zumindest mal ein paar Ausgangspunkte haben.

Das Problem war, dass ich im Rückblick auf meinen ersten Ansatz sehr viele Dinge falsch angegangen bin, und wenn man nur einen Fehler behebt, die Bewegung noch immer total unlogisch verläuft. Deshalb ist es schwer, eine Fehlerquelle allein durch Ausprobieren auszuheben.

Wie man den Winkel zwischen zwei Punkten herausfinden kann:


      double TanWinkel;

      if (DeltaX() == 0)
        TanWinkel = 0;
      else
        TanWinkel = DeltaY() / DeltaX();

      double Winkel = Math.Atan(TanWinkel);

Wichtig ist hierbei zu schauen, dass DeltaX nicht Null werden darf. DeltaX und DeltaY steht jeweils für die Differenz zwischen der X- bzw. Y-Koordinate von Position und Ziel. Der Cosinus und Sinus des Winkels fließen dann in die obere Formel ein. Einfachheitshalber mache ich Folgendes:


      if (DeltaX() == 0)
      {
        CosWinkel = 0;
        SinWinkel = 1;
      }

      if (DeltaY() == 0)
      {
        CosWinkel = 1;
        SinWinkel = 0;
      }

Das bedeutet, dass wenn das Ziel sich nur in einer der beiden Achsen vom Ursprung unterscheidet, die betroffene Koordinate konstant bleibt.

Beispiel:
Aktuelle Position ist 100/200 und das Ziel hat die Koordinaten 100/400. Das Objekt würde sich also nur auf der X-Achse verschieben. Es wandert also nach rechts, bildlich gesprochen. Damit wird DeltaX = 0. Nach meinem Code wird damit auch der Cosinus = 0, was dazu führt, dass die Formel

NextPosX = StartPosX + Speed * Zeit * CosWinkel;

immer den Wert der Startposition behält. Im Fall des Beispiels 100.

Was genau ist die Zeit?

Die Zeit in der Formel ist die Zeit, die seit dem Start der Bewegung vergangen ist. In meinem Beispiel lasse ich die Bewegung erst nach einer Sekunde starten. Dementsprechend fängt die Zeit auch erst an, nachdem eine Sekunde vergangen ist:


    private double ZeitSeitBewegung(bool Set)
    {
      if (Set)
      {
        if (ZeitpunktBewegung == 0)
          ZeitpunktBewegung = ClassGlobal.SITime();
      }

      double ZeitSeitBeweg = ClassGlobal.SITime() - ZeitpunktBewegung;

      return ZeitSeitBeweg;
    }

SiTime() ist die Zeit, die seit Programmstart vergangen ist, in Sekunden. ZeitpunktBewegung ist ein Feld des Objekts.

Ich habe das Setzen der Zeit mit einer Variable "Set" geknüpft, da die Funktion später noch mal aufgerufen wird, um die aktuelle Zeit auszugeben, aber hier die Zeit nicht gesetzt werden soll.

Problem: Mein Objekt schießt über das Ziel hinaus und verhält sich danach komisch.

Um dieses Problem abzufangen, muss überprüft werden, ob das Objekt nicht im nächsten Schritt über das Ziel hinausschießt. Das Ziel pixelgenau zu treffen ist sehr unwahrscheinlich. Daher folgender Code:


      if (CosWinkel == 0)   
      {
        if ((ZielY >= PosY && ZielY <= NextPosY) || (ZielY <= PosY && ZielY > NextPosY))
        {
          ZielWurdeErreicht();
          return true;
        }
      }
      else if (SinWinkel == 0)
      {
        if ((ZielX >= PosX && ZielX <= NextPosX) || (ZielX <= PosX && ZielX > NextPosX))
        {
          ZielWurdeErreicht();
          return true;
        }
      }
      else
      {
        // wenn das Ziel zwischen der aktuellen und der nächsten Position liegt
        if ((ZielX >= PosX && ZielX <= NextPosX) || (ZielY >= PosY && ZielY <= NextPosY) ||
          (ZielX <= PosX && ZielX > NextPosX) || (ZielY <= PosY && ZielY > NextPosY))
        {
          ZielWurdeErreicht();
          return true;
        }
      }

Die Fallunterscheidung hängt mit dem oben beschriebenen Fall zusammen, dass sich das Objekt nur auf einer Achse bewegt. Für einen solchen Fall testen wir einfach, ob das Objekt mit dem nächsten Schritt auf der anderen Achse das Ziel überschreiten würde. Ansonsten wird geprüft, ob das Ziel auf einer der beiden Achsen überschritten werden würde. Normalerweise sollte es auf beiden Achsen gleichzeitig überschritten werden. Aber das trifft wahrscheinlich nur bei sehr kleinen (oder großen?) Bewegungseinheiten zu.

Ich hoffe, ich konnte meine Überlegungen verständlich machen, und dieser Beitrag dem ein oder anderen hilft. Ich hoffe auch, dass auf meiner Seite diesbezüglich keine weiteren Probleme mehr auftreten.

Jack

edit: Ach ja. Und Danke noch mal an alle, die mir hier geholfen haben! Ohne euren "Stupps in die richtige Richtung zur richtigen Zeit" hätte ich das wahrscheinlich nie hinbekommen und aufgegeben. 😉