Ich entschuldige mich, wenn ich den Begriff "Einheitsvektor" falsch verstanden oder im Konzept falsch angewendet habe, aber ich denke, dass dies der Begriff für die Überschrift eines Objekts ist, wenn er als [x, y]
wann ausgedrückt wird x
und y
ein Wert zwischen -1 und 1 ist. Wenn sich ein Objekt auf einem Computerbildschirm nach Süden bewegen würde, hätte es einen Einheitsvektor von
[0, 1]
...Recht?
Wie auch immer, ich habe dieses Konzept verwendet, um meine Objekte zu bewegen und ihre Bilder zu drehen (falls erforderlich), aber ich denke, die Mathematik, mit der ich den Einheitsvektor bestimme, ist ... suboptimal.
def set_heading(self, goal):
"""Uses a 'goal' (x, y) to set the object's heading.
Returns list of 0s and 1s for 'straight' headings.
Diagonal headings are + and/or - math.sqrt(2)/2.
"""
vals = [a - b for a, b in zip(goal, self.pos)]
self.heading = [i / abs(i) if i != 0 else 0 for i in vals]
if 0 not in self.heading:
self.heading = [i * (sqrt(2)/2) for i in self.heading]
(Wenn Sie mit der ternären Python-Syntax nicht vertraut sind, enthält i / abs(i) if i != 0 else 0
die zweite Zeile die Art und Weise, x if Condition else y
wie Python im Gegensatz zur üblichen Condition? x : else y
Syntax in anderen Sprachen sagt . Grundsätzlich versuche ich nur, das Teilen durch Null zu vermeiden!)
Wie Sie sehen können, sperrt diese Methode das Objekt in acht Richtungen. Wenn in der Überschrift keine 0 vorhanden ist, geht die Methode davon aus, dass wir uns diagonal sqrt(2) / 2
bewegen, und multipliziert die Werte damit, um sicherzustellen, dass sich das Objekt nicht schneller bewegt, als es sollte, wenn es sich diagonal bewegt. Auf diese Weise kann ich das Objekt bewegen, indem ich einfach das Ergebnis des Einheitsvektors multipliziert mit seiner Geschwindigkeit zu seinen aktuellen x- und y-Koordinaten addiere.
def move(self):
"""Moves the object by changing self.pos."""
self.pos = [a + (b * self.speed) for a, b in zip(self.pos, self.heading)]
Ich kann nicht anders, als das Gefühl zu haben, dass die Methode zum Abrufen des Einheitsvektors (wenn das richtig heißt) sophomorisch ist. Zumal es in acht Richtungen verriegelt ist - es ist in Ordnung für das kleine Projekt, mit dem ich gerade arbeite, aber ich bin mir nicht sicher, wie ich einen genaueren Einheitsvektor erhalten soll. Was ist die richtige Methode dafür - und ist sie mehr oder weniger performant als die Verrücktheit, die ich mir unabhängig ausgedacht habe?
Antworten:
Ein Einheitsvektor hat die Länge 1.
Ein gegebener Vektor kann in einen Einheitsvektor umgewandelt werden, indem er durch seine Größe dividiert wird. (Mit der Ausnahme, dass ein Vektor mit der Länge Null nicht konvertiert werden kann).
Beachten Sie, dass die Größe mit dem Satz von Pythagoras berechnet werden kann
Zum Beispiel, wenn ein Vektor Komponenten hat: (
x, y, z
)magnitude = sqrt( x
2
+ y
2
+ z
2
)
unit vector = ( x / magnitude , y / magnitude, z / magnitude )
Annan wirft einen interessanten Punkt auf, der bei Vektoren mit einer Größe größer als
math.sqrt(sys.float_info.max)
(ungefähr 1,3e + 154 auf meinem Computer) fehlschlägt, wenn Floats auf normale Weise verwendet werden. In diesem Fall ist eine Problemumgehung, bei der Longs verwendet werden, um die Arbeitswerte zu halten und dann die Quadratwurzel manuell zu finden, funktionsfähig, aber relativ langsam.Die Gutschrift für diese Implementierung der Newtonschen Methode geht an user448810 .
quelle
sqrt()
aus der Logik herauszuholen (und daher nicht mehr ausschließlich mit Einheitsvektoren zu arbeiten) oder ist dies eine akzeptable Verwendung dafürsqrt()
. Was in Ordnung ist - ich codiere nicht fürsys.float_info.max
(ungefähr 1,7e + 308 auf meinem Computer) verarbeitet. Darüber hinaus möchten Sie wahrscheinlich ohnehin einen langbasierten Vektor verwenden.