-
Notifications
You must be signed in to change notification settings - Fork 90
Expand file tree
/
Copy pathvec.py
More file actions
109 lines (82 loc) · 3.63 KB
/
vec.py
File metadata and controls
109 lines (82 loc) · 3.63 KB
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
import math
from typing import Union
from rlbot.utils.structures.game_data_struct import Vector3
class Vec3:
"""
This class should provide you with all the basic vector operations that you need, but feel free to extend its
functionality when needed.
The vectors found in the GameTickPacket will be flatbuffer vectors. Cast them to Vec3 like this:
`car_location = Vec3(car.physics.location)`.
Remember that the in-game axis are left-handed.
When in doubt visit the wiki: https://github.com/RLBot/RLBot/wiki/Useful-Game-Values
"""
# https://docs.python.org/3/reference/datamodel.html#slots
__slots__ = [
'x',
'y',
'z'
]
def __init__(self, x: Union[float, 'Vec3', 'Vector3']=0, y: float=0, z: float=0):
"""
Create a new Vec3. The x component can alternatively be another vector with an x, y, and z component, in which
case the created vector is a copy of the given vector and the y and z parameter is ignored. Examples:
a = Vec3(1, 2, 3)
b = Vec3(a)
"""
if hasattr(x, 'x'):
# We have been given a vector. Copy it
self.x = float(x.x)
self.y = float(x.y) if hasattr(x, 'y') else 0
self.z = float(x.z) if hasattr(x, 'z') else 0
else:
self.x = float(x)
self.y = float(y)
self.z = float(z)
def __getitem__(self, item: int):
return (self.x, self.y, self.z)[item]
def __add__(self, other: 'Vec3') -> 'Vec3':
return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
def __sub__(self, other: 'Vec3') -> 'Vec3':
return Vec3(self.x - other.x, self.y - other.y, self.z - other.z)
def __neg__(self):
return Vec3(-self.x, -self.y, -self.z)
def __mul__(self, scale: float) -> 'Vec3':
return Vec3(self.x * scale, self.y * scale, self.z * scale)
def __rmul__(self, scale):
return self * scale
def __truediv__(self, scale: float) -> 'Vec3':
scale = 1 / float(scale)
return self * scale
def __str__(self):
return f"Vec3({self.x:.2f}, {self.y:.2f}, {self.z:.2f})"
def __repr__(self):
return self.__str__()
def flat(self):
"""Returns a new Vec3 that equals this Vec3 but projected onto the ground plane. I.e. where z=0."""
return Vec3(self.x, self.y, 0)
def length(self):
"""Returns the length of the vector. Also called magnitude and norm."""
return math.sqrt(self.x**2 + self.y**2 + self.z**2)
def dist(self, other: 'Vec3') -> float:
"""Returns the distance between this vector and another vector using pythagoras."""
return (self - other).length()
def normalized(self):
"""Returns a vector with the same direction but a length of one."""
return self / self.length()
def rescale(self, new_len: float) -> 'Vec3':
"""Returns a vector with the same direction but a different length."""
return new_len * self.normalized()
def dot(self, other: 'Vec3') -> float:
"""Returns the dot product."""
return self.x*other.x + self.y*other.y + self.z*other.z
def cross(self, other: 'Vec3') -> 'Vec3':
"""Returns the cross product."""
return Vec3(
self.y * other.z - self.z * other.y,
self.z * other.x - self.x * other.z,
self.x * other.y - self.y * other.x
)
def ang_to(self, ideal: 'Vec3') -> float:
"""Returns the angle to the ideal vector. Angle will be between 0 and pi."""
cos_ang = self.dot(ideal) / (self.length() * ideal.length())
return math.acos(cos_ang)