e2D 1.4.18__tar.gz → 1.4.23__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {e2d-1.4.18 → e2d-1.4.23}/LICENSE +21 -21
- {e2d-1.4.18 → e2d-1.4.23}/PKG-INFO +3 -2
- {e2d-1.4.18 → e2d-1.4.23}/e2D/__init__.py +82 -32
- {e2d-1.4.18 → e2d-1.4.23}/e2D/__init__.pyi +295 -7
- {e2d-1.4.18 → e2d-1.4.23}/e2D/colors.py +53 -23
- {e2d-1.4.18 → e2d-1.4.23}/e2D/envs.py +91 -35
- e2d-1.4.23/e2D/utils.py +581 -0
- e2d-1.4.23/e2D/winrec.py +212 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D.egg-info/PKG-INFO +3 -2
- {e2d-1.4.18 → e2d-1.4.23}/setup.cfg +1 -1
- e2d-1.4.18/e2D/utils.py +0 -191
- e2d-1.4.18/e2D/winrec.py +0 -27
- {e2d-1.4.18 → e2d-1.4.23}/README.md +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D/def_colors.py +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D/plots.py +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D.egg-info/SOURCES.txt +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D.egg-info/dependency_links.txt +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D.egg-info/requires.txt +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/e2D.egg-info/top_level.txt +0 -0
- {e2d-1.4.18 → e2d-1.4.23}/pyproject.toml +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Riccardo Mariani
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: e2D
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.23
|
|
4
4
|
Summary: Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
|
|
5
5
|
Home-page: https://github.com/marick-py/e2D
|
|
6
6
|
Author: Riccardo Mariani
|
|
@@ -13,6 +13,7 @@ Description-Content-Type: text/markdown
|
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: pygame
|
|
16
|
+
Dynamic: license-file
|
|
16
17
|
|
|
17
18
|
# e2D
|
|
18
19
|
## A Python Game Development Library
|
|
@@ -10,6 +10,7 @@ PI_QUARTER = PI/4
|
|
|
10
10
|
PI_DOUBLE = PI*2
|
|
11
11
|
|
|
12
12
|
sign = lambda val: -1 if val < 0 else (1 if val > 0 else 0)
|
|
13
|
+
clamp = lambda x, minn, maxx: x if x > minn and x < maxx else (minn if x < minn else maxx)
|
|
13
14
|
|
|
14
15
|
class Vector2D:
|
|
15
16
|
round_values_on_print = 2
|
|
@@ -17,7 +18,7 @@ class Vector2D:
|
|
|
17
18
|
self.x = x
|
|
18
19
|
self.y = y
|
|
19
20
|
|
|
20
|
-
def distance_to(self, other, rooted=True) -> float:
|
|
21
|
+
def distance_to(self, other, rooted=True) -> int|float:
|
|
21
22
|
d = (self.x - other.x)**2 + (self.y - other.y)**2
|
|
22
23
|
return d**(1/2) if rooted else d
|
|
23
24
|
|
|
@@ -34,29 +35,71 @@ class Vector2D:
|
|
|
34
35
|
@angle.setter
|
|
35
36
|
def angle(self, new_angle) -> None:
|
|
36
37
|
self.rotate(new_angle - self.angle)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def aspect_x(self) -> float:
|
|
41
|
+
return self.x / self.y if self.y != 0 else 0
|
|
42
|
+
|
|
43
|
+
@aspect_x.setter
|
|
44
|
+
def aspect_x(self, new_aspect) -> None:
|
|
45
|
+
self.x = self.y * new_aspect
|
|
37
46
|
|
|
38
47
|
@property
|
|
48
|
+
def aspect_y(self) -> float:
|
|
49
|
+
return self.y / self.x if self.x != 0 else 0
|
|
50
|
+
|
|
51
|
+
@aspect_y.setter
|
|
52
|
+
def aspect_y(self, new_aspect) -> None:
|
|
53
|
+
self.y = self.x * new_aspect
|
|
54
|
+
|
|
39
55
|
def copy(self) -> "Vector2D":
|
|
40
56
|
return Vector2D(self.x, self.y)
|
|
41
57
|
|
|
42
58
|
@property
|
|
43
59
|
def sign(self) -> "Vector2D":
|
|
44
60
|
return Vector2D(sign(self.x), sign(self.y))
|
|
61
|
+
|
|
62
|
+
def clamp(self, min_val: Vector2D, max_val: Vector2D) -> "Vector2D":
|
|
63
|
+
return Vector2D(clamp(self.x, min_val.x, max_val.x), clamp(self.y, min_val.y, max_val.y))
|
|
64
|
+
|
|
65
|
+
def iclamp(self, min_val: Vector2D, max_val: Vector2D) -> None:
|
|
66
|
+
self.x = clamp(self.x, min_val.x, max_val.x)
|
|
67
|
+
self.y = clamp(self.y, min_val.y, max_val.y)
|
|
45
68
|
|
|
46
69
|
@property
|
|
47
|
-
def
|
|
70
|
+
def normalized(self) -> "Vector2D":
|
|
48
71
|
if (mag:=self.length) == 0:
|
|
49
|
-
return self.copy
|
|
72
|
+
return self.copy()
|
|
50
73
|
return Vector2D(self.x / mag, self.y / mag)
|
|
51
74
|
|
|
52
75
|
@property
|
|
53
76
|
def length(self) -> float:
|
|
54
77
|
return (self.x ** 2 + self.y ** 2) ** .5
|
|
55
|
-
|
|
78
|
+
|
|
79
|
+
@length.setter
|
|
80
|
+
def length(self, new_length: float) -> None:
|
|
81
|
+
current_length = self.length
|
|
82
|
+
if current_length == 0:
|
|
83
|
+
self.x = new_length
|
|
84
|
+
self.y = 0
|
|
85
|
+
else:
|
|
86
|
+
self.x *= new_length / current_length
|
|
87
|
+
self.y *= new_length / current_length
|
|
88
|
+
|
|
56
89
|
@property
|
|
57
90
|
def length_sqrd(self) -> float:
|
|
58
91
|
return self.x ** 2 + self.y ** 2
|
|
59
|
-
|
|
92
|
+
|
|
93
|
+
@length_sqrd.setter
|
|
94
|
+
def length_sqrd(self, new_length_sqrd: float) -> None:
|
|
95
|
+
current_length = self.length
|
|
96
|
+
if current_length == 0:
|
|
97
|
+
self.x = _mt.sqrt(new_length_sqrd)
|
|
98
|
+
self.y = 0
|
|
99
|
+
else:
|
|
100
|
+
self.x *= _mt.sqrt(new_length_sqrd) / current_length
|
|
101
|
+
self.y *= _mt.sqrt(new_length_sqrd) / current_length
|
|
102
|
+
|
|
60
103
|
@property
|
|
61
104
|
def inverse(self) -> "Vector2D":
|
|
62
105
|
return self.mult(-1)
|
|
@@ -71,7 +114,7 @@ class Vector2D:
|
|
|
71
114
|
return self.__round__(n)
|
|
72
115
|
|
|
73
116
|
@classmethod
|
|
74
|
-
def randomize(cls, start, end) -> "Vector2D":
|
|
117
|
+
def randomize(cls, start, end, func=lambda val:val) -> "Vector2D":
|
|
75
118
|
if not isinstance(start, Vector2D):
|
|
76
119
|
if isinstance(start, (int, float)):
|
|
77
120
|
start = Vector2D(start, start)
|
|
@@ -82,7 +125,7 @@ class Vector2D:
|
|
|
82
125
|
end = Vector2D(end, end)
|
|
83
126
|
else:
|
|
84
127
|
raise Exception(f"\nArg end must be in [Vector2D, int, float, tuple, list] not a [{type(end)}]\n")
|
|
85
|
-
return start + Vector2D(_rnd.random(), _rnd.random()) * (end - start)
|
|
128
|
+
return start + Vector2D(func(_rnd.random()), func(_rnd.random())) * (end - start)
|
|
86
129
|
|
|
87
130
|
def dot_product(self, other) -> float:
|
|
88
131
|
return self.x * other.x + self.y * other.y
|
|
@@ -111,6 +154,13 @@ class Vector2D:
|
|
|
111
154
|
def complex_to_cartesian(cls, complex_n) -> "Vector2D":
|
|
112
155
|
return cls(complex_n.real, complex_n.imag)
|
|
113
156
|
|
|
157
|
+
def cartesian_to_linear(self, size) -> int:
|
|
158
|
+
return int(self.x + self.y * size)
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def linear_to_cartesian(cls, linear, size) -> "Vector2D":
|
|
162
|
+
return cls(linear % size, linear // size)
|
|
163
|
+
|
|
114
164
|
def lerp(self, other, t=.1) -> "Vector2D":
|
|
115
165
|
return Vector2D(self.x + (other.x - self.x) * t, self.y + (other.y - self.y) * t)
|
|
116
166
|
|
|
@@ -420,47 +470,47 @@ class Vector2D:
|
|
|
420
470
|
def down_left_norm(cls) -> "Vector2D": return V2down_left_norm
|
|
421
471
|
|
|
422
472
|
@classmethod
|
|
423
|
-
def new_zero(cls) -> "Vector2D": return V2zero.copy
|
|
473
|
+
def new_zero(cls) -> "Vector2D": return V2zero.copy()
|
|
424
474
|
@classmethod
|
|
425
|
-
def new_one(cls) -> "Vector2D": return V2one.copy
|
|
475
|
+
def new_one(cls) -> "Vector2D": return V2one.copy()
|
|
426
476
|
@classmethod
|
|
427
|
-
def new_two(cls) -> "Vector2D": return V2two.copy
|
|
477
|
+
def new_two(cls) -> "Vector2D": return V2two.copy()
|
|
428
478
|
@classmethod
|
|
429
|
-
def new_pi(cls) -> "Vector2D": return V2pi.copy
|
|
479
|
+
def new_pi(cls) -> "Vector2D": return V2pi.copy()
|
|
430
480
|
@classmethod
|
|
431
|
-
def new_inf(cls) -> "Vector2D": return V2inf.copy
|
|
481
|
+
def new_inf(cls) -> "Vector2D": return V2inf.copy()
|
|
432
482
|
@classmethod
|
|
433
|
-
def new_neg_one(cls) -> "Vector2D": return V2neg_one.copy
|
|
483
|
+
def new_neg_one(cls) -> "Vector2D": return V2neg_one.copy()
|
|
434
484
|
@classmethod
|
|
435
|
-
def new_neg_two(cls) -> "Vector2D": return V2neg_two.copy
|
|
485
|
+
def new_neg_two(cls) -> "Vector2D": return V2neg_two.copy()
|
|
436
486
|
@classmethod
|
|
437
|
-
def new_neg_pi(cls) -> "Vector2D": return V2neg_pi.copy
|
|
487
|
+
def new_neg_pi(cls) -> "Vector2D": return V2neg_pi.copy()
|
|
438
488
|
@classmethod
|
|
439
|
-
def new_neg_inf(cls) -> "Vector2D": return V2neg_inf.copy
|
|
489
|
+
def new_neg_inf(cls) -> "Vector2D": return V2neg_inf.copy()
|
|
440
490
|
@classmethod
|
|
441
|
-
def new_up(cls) -> "Vector2D": return V2up.copy
|
|
491
|
+
def new_up(cls) -> "Vector2D": return V2up.copy()
|
|
442
492
|
@classmethod
|
|
443
|
-
def new_right(cls) -> "Vector2D": return V2right.copy
|
|
493
|
+
def new_right(cls) -> "Vector2D": return V2right.copy()
|
|
444
494
|
@classmethod
|
|
445
|
-
def new_down(cls) -> "Vector2D": return V2down.copy
|
|
495
|
+
def new_down(cls) -> "Vector2D": return V2down.copy()
|
|
446
496
|
@classmethod
|
|
447
|
-
def new_left(cls) -> "Vector2D": return V2left.copy
|
|
497
|
+
def new_left(cls) -> "Vector2D": return V2left.copy()
|
|
448
498
|
@classmethod
|
|
449
|
-
def new_up_right(cls) -> "Vector2D": return V2up_right.copy
|
|
499
|
+
def new_up_right(cls) -> "Vector2D": return V2up_right.copy()
|
|
450
500
|
@classmethod
|
|
451
|
-
def new_down_right(cls) -> "Vector2D": return V2down_right.copy
|
|
501
|
+
def new_down_right(cls) -> "Vector2D": return V2down_right.copy()
|
|
452
502
|
@classmethod
|
|
453
|
-
def new_up_left(cls) -> "Vector2D": return V2up_left.copy
|
|
503
|
+
def new_up_left(cls) -> "Vector2D": return V2up_left.copy()
|
|
454
504
|
@classmethod
|
|
455
|
-
def new_down_left(cls) -> "Vector2D": return V2down_left.copy
|
|
505
|
+
def new_down_left(cls) -> "Vector2D": return V2down_left.copy()
|
|
456
506
|
@classmethod
|
|
457
|
-
def new_up_right_norm(cls) -> "Vector2D": return V2up_right_norm.copy
|
|
507
|
+
def new_up_right_norm(cls) -> "Vector2D": return V2up_right_norm.copy()
|
|
458
508
|
@classmethod
|
|
459
|
-
def new_down_right_norm(cls) -> "Vector2D": return V2down_right_norm.copy
|
|
509
|
+
def new_down_right_norm(cls) -> "Vector2D": return V2down_right_norm.copy()
|
|
460
510
|
@classmethod
|
|
461
|
-
def new_up_left_norm(cls) -> "Vector2D": return V2up_left_norm.copy
|
|
511
|
+
def new_up_left_norm(cls) -> "Vector2D": return V2up_left_norm.copy()
|
|
462
512
|
@classmethod
|
|
463
|
-
def new_down_left_norm(cls) -> "Vector2D": return V2down_left_norm.copy
|
|
513
|
+
def new_down_left_norm(cls) -> "Vector2D": return V2down_left_norm.copy()
|
|
464
514
|
|
|
465
515
|
|
|
466
516
|
V2 = Vector2D
|
|
@@ -487,10 +537,10 @@ V2down_right = Vector2D(1, -1)
|
|
|
487
537
|
V2up_left = Vector2D(-1, 1)
|
|
488
538
|
V2down_left = Vector2D(-1, -1)
|
|
489
539
|
|
|
490
|
-
V2up_right_norm = V2up_right.
|
|
491
|
-
V2down_right_norm = V2down_right.
|
|
492
|
-
V2up_left_norm = V2up_left.
|
|
493
|
-
V2down_left_norm = V2down_left.
|
|
540
|
+
V2up_right_norm = V2up_right.normalized
|
|
541
|
+
V2down_right_norm = V2down_right.normalized
|
|
542
|
+
V2up_left_norm = V2up_left.normalized
|
|
543
|
+
V2down_left_norm = V2down_left.normalized
|
|
494
544
|
|
|
495
545
|
VECTORS_4_DIRECTIONS = (V2right, V2down, V2left, V2up)
|
|
496
546
|
VECTORS_4_SEMIDIRECTIONS = (V2down_right, V2down_left, V2up_left, V2up_right)
|
|
@@ -12,6 +12,7 @@ PI_DOUBLE : float
|
|
|
12
12
|
#
|
|
13
13
|
|
|
14
14
|
sign : Callable[[int|float], Literal[-1,0,1]]
|
|
15
|
+
clamp: Callable[[int|float, int|float, int|float], int|float]
|
|
15
16
|
|
|
16
17
|
class Vector2D:
|
|
17
18
|
round_values_on_print : int|float
|
|
@@ -39,7 +40,7 @@ class Vector2D:
|
|
|
39
40
|
self.x : int|float
|
|
40
41
|
self.y : int|float
|
|
41
42
|
|
|
42
|
-
def distance_to(self:"Vector2D", other:"Vector2D", rooted:bool=True) -> float:
|
|
43
|
+
def distance_to(self:"Vector2D", other:"Vector2D", rooted:bool=True) -> int|float:
|
|
43
44
|
"""
|
|
44
45
|
# Calculate the distance between the current Vector2D other and another other.
|
|
45
46
|
|
|
@@ -140,12 +141,60 @@ class Vector2D:
|
|
|
140
141
|
...
|
|
141
142
|
|
|
142
143
|
@property
|
|
143
|
-
def angle(self:"Vector2D") -> int|float:
|
|
144
|
+
def angle(self:"Vector2D") -> int|float:
|
|
145
|
+
"""
|
|
146
|
+
# Vector Angle
|
|
147
|
+
## Returns:
|
|
148
|
+
float: The angle (in radians) of the vector from the positive x-axis.
|
|
149
|
+
## Example:
|
|
150
|
+
v = Vector2D(1, 1)
|
|
151
|
+
angle = v.angle
|
|
152
|
+
print(angle) # Output: 0.7853981633974483
|
|
153
|
+
## Explanation:
|
|
154
|
+
This property calculates the angle of the vector from the positive x-axis using the `atan2` function.
|
|
155
|
+
"""
|
|
156
|
+
...
|
|
144
157
|
|
|
145
158
|
@angle.setter
|
|
146
|
-
def angle(self:"Vector2D", argv) -> None:
|
|
159
|
+
def angle(self:"Vector2D", argv) -> None:
|
|
160
|
+
...
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def aspect_x(self: "Vector2D") -> float:
|
|
164
|
+
"""
|
|
165
|
+
# Aspect Ratio (X over Y)
|
|
166
|
+
## Returns:
|
|
167
|
+
float: The aspect ratio of the vector, calculated as the x component divided by the y component. Returns 0 if the y component is zero.
|
|
168
|
+
## Example:
|
|
169
|
+
v = Vector2D(4, 2)
|
|
170
|
+
aspect = v.aspect_x
|
|
171
|
+
print(aspect) # Output: 2.0
|
|
172
|
+
## Explanation:
|
|
173
|
+
This property computes the ratio of the x component to the y component of the vector. If the y component is zero, it returns 0 to avoid division by zero.
|
|
174
|
+
"""
|
|
175
|
+
...
|
|
176
|
+
|
|
177
|
+
@aspect_x.setter
|
|
178
|
+
def aspect_x(self: "Vector2D", new_aspect) -> None: ...
|
|
147
179
|
|
|
148
180
|
@property
|
|
181
|
+
def aspect_y(self: "Vector2D") -> float:
|
|
182
|
+
"""
|
|
183
|
+
# Aspect Ratio (Y over X)
|
|
184
|
+
## Returns:
|
|
185
|
+
float: The aspect ratio of the vector, calculated as the y component divided by the x component. Returns 0 if the x component is zero.
|
|
186
|
+
## Example:
|
|
187
|
+
v = Vector2D(2, 4)
|
|
188
|
+
aspect = v.aspect_y
|
|
189
|
+
print(aspect) # Output: 2.0
|
|
190
|
+
## Explanation:
|
|
191
|
+
This property computes the ratio of the y component to the x component of the vector. If the x component is zero, it returns 0 to avoid division by zero.
|
|
192
|
+
"""
|
|
193
|
+
...
|
|
194
|
+
|
|
195
|
+
@aspect_y.setter
|
|
196
|
+
def aspect_y(self: "Vector2D", new_aspect) -> None: ...
|
|
197
|
+
|
|
149
198
|
def copy(self:"Vector2D") -> "Vector2D":
|
|
150
199
|
"""
|
|
151
200
|
# Create a copy of the current Vector2D other.
|
|
@@ -211,8 +260,56 @@ class Vector2D:
|
|
|
211
260
|
"""
|
|
212
261
|
...
|
|
213
262
|
|
|
263
|
+
def clamp(self, min_val: Vector2D, max_val: Vector2D) -> "Vector2D":
|
|
264
|
+
"""
|
|
265
|
+
# Clamp the vector's components between the corresponding components of two other vectors.
|
|
266
|
+
|
|
267
|
+
## Parameters:
|
|
268
|
+
min_val (Vector2D): The minimum vector for clamping.
|
|
269
|
+
max_val (Vector2D): The maximum vector for clamping.
|
|
270
|
+
|
|
271
|
+
## Returns:
|
|
272
|
+
Vector2D: A new vector with its components clamped between the corresponding components of `min_val` and `max_val`.
|
|
273
|
+
|
|
274
|
+
## Example:
|
|
275
|
+
v = Vector2D(5, 10)
|
|
276
|
+
min_val = Vector2D(0, 8)
|
|
277
|
+
max_val = Vector2D(6, 12)
|
|
278
|
+
clamped_v = v.clamp(min_val, max_val)
|
|
279
|
+
print(clamped_v) # Output: (5, 10)
|
|
280
|
+
|
|
281
|
+
## Explanation:
|
|
282
|
+
This method clamps the x and y components of the current vector between the corresponding x and y components
|
|
283
|
+
of the `min_val` and `max_val` vectors. The resulting vector is returned as a new Vector2D instance.
|
|
284
|
+
"""
|
|
285
|
+
...
|
|
286
|
+
|
|
287
|
+
def iclamp(self, min_val: Vector2D, max_val: Vector2D) -> None:
|
|
288
|
+
"""
|
|
289
|
+
# Clamp the vector's components in place between the corresponding components of two other vectors.
|
|
290
|
+
|
|
291
|
+
## Parameters:
|
|
292
|
+
min_val (Vector2D): The minimum vector for clamping.
|
|
293
|
+
max_val (Vector2D): The maximum vector for clamping.
|
|
294
|
+
|
|
295
|
+
## Returns:
|
|
296
|
+
None
|
|
297
|
+
|
|
298
|
+
## Example:
|
|
299
|
+
v = Vector2D(5, 10)
|
|
300
|
+
min_val = Vector2D(0, 8)
|
|
301
|
+
max_val = Vector2D(6, 12)
|
|
302
|
+
v.iclamp(min_val, max_val)
|
|
303
|
+
print(v) # Output: (5, 10)
|
|
304
|
+
|
|
305
|
+
## Explanation:
|
|
306
|
+
This method clamps the x and y components of the current vector in place between the corresponding x and y components
|
|
307
|
+
of the `min_val` and `max_val` vectors. The method modifies the current vector directly.
|
|
308
|
+
"""
|
|
309
|
+
...
|
|
310
|
+
|
|
214
311
|
@property
|
|
215
|
-
def
|
|
312
|
+
def normalized(self:"Vector2D") -> "Vector2D":
|
|
216
313
|
"""
|
|
217
314
|
# Vector Normalization
|
|
218
315
|
|
|
@@ -224,7 +321,7 @@ class Vector2D:
|
|
|
224
321
|
|
|
225
322
|
## Example:
|
|
226
323
|
v = Vector2D(3, 4)
|
|
227
|
-
normalized_v = v.
|
|
324
|
+
normalized_v = v.normalized() # Normalize the vector (3, 4)
|
|
228
325
|
print(normalized_v) # Output: (0.6, 0.8)
|
|
229
326
|
|
|
230
327
|
## Explanation:
|
|
@@ -244,27 +341,127 @@ class Vector2D:
|
|
|
244
341
|
|
|
245
342
|
@property
|
|
246
343
|
def length(self:"Vector2D") -> float:
|
|
344
|
+
"""
|
|
345
|
+
# Vector Length
|
|
346
|
+
|
|
347
|
+
## Returns:
|
|
348
|
+
float: The length (magnitude) of the vector.
|
|
349
|
+
|
|
350
|
+
## Example:
|
|
351
|
+
v = Vector2D(3, 4)
|
|
352
|
+
length = v.length
|
|
353
|
+
print(length) # Output: 5.0
|
|
354
|
+
|
|
355
|
+
## Explanation:
|
|
356
|
+
This property calculates the length (magnitude) of the vector using the Pythagorean theorem.
|
|
357
|
+
"""
|
|
247
358
|
...
|
|
248
359
|
|
|
249
360
|
@property
|
|
250
361
|
def length_sqrd(self:"Vector2D") -> float:
|
|
362
|
+
"""
|
|
363
|
+
# Vector Length Squared
|
|
364
|
+
|
|
365
|
+
## Returns:
|
|
366
|
+
float: The squared length (magnitude) of the vector.
|
|
367
|
+
|
|
368
|
+
## Example:
|
|
369
|
+
v = Vector2D(3, 4)
|
|
370
|
+
length_sqrd = v.length_sqrd
|
|
371
|
+
print(length_sqrd) # Output: 25
|
|
372
|
+
|
|
373
|
+
## Explanation:
|
|
374
|
+
This property calculates the squared length (magnitude) of the vector.
|
|
375
|
+
It is more efficient than calculating the actual length, as it avoids the
|
|
376
|
+
square root calculation.
|
|
377
|
+
"""
|
|
251
378
|
...
|
|
252
379
|
|
|
253
380
|
@property
|
|
254
381
|
def inverse(self:"Vector2D") -> "Vector2D":
|
|
382
|
+
"""
|
|
383
|
+
# Vector Inversion
|
|
384
|
+
|
|
385
|
+
## Returns:
|
|
386
|
+
Vector2D: A new vector with inverted components.
|
|
387
|
+
|
|
388
|
+
## Example:
|
|
389
|
+
v = Vector2D(3, 4)
|
|
390
|
+
inverted_v = v.inverse()
|
|
391
|
+
print(inverted_v) # Output: (-3, -4)
|
|
392
|
+
|
|
393
|
+
## Explanation:
|
|
394
|
+
This method calculates the inverted version of the current vector, which means a new vector with the same magnitude
|
|
395
|
+
but opposite direction.
|
|
396
|
+
|
|
397
|
+
The inverted vector is obtained by negating each component of the current vector.
|
|
398
|
+
|
|
399
|
+
The resulting inverted vector is returned.
|
|
400
|
+
"""
|
|
255
401
|
...
|
|
256
402
|
|
|
257
403
|
def floor(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
|
|
404
|
+
"""
|
|
405
|
+
# Round the Vector2D components down to the nearest integer or specified decimal place.
|
|
406
|
+
|
|
407
|
+
## Parameters:
|
|
408
|
+
n (int|float|Vector2D, optional): The decimal place to round down to. Default is 1.
|
|
409
|
+
|
|
410
|
+
## Returns:
|
|
411
|
+
Vector2D: A new vector with rounded-down components.
|
|
412
|
+
|
|
413
|
+
## Example:
|
|
414
|
+
v = Vector2D(3.14159, 2.71828)
|
|
415
|
+
rounded_v = v.floor(2)
|
|
416
|
+
print(rounded_v) # Output: (3.14, 2.71)
|
|
417
|
+
|
|
418
|
+
## Explanation:
|
|
419
|
+
This method rounds each component of the vector down to the nearest integer or specified decimal place.
|
|
420
|
+
"""
|
|
258
421
|
...
|
|
259
422
|
|
|
260
423
|
def ceil(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
|
|
424
|
+
"""
|
|
425
|
+
# Round the Vector2D components up to the nearest integer or specified decimal place.
|
|
426
|
+
|
|
427
|
+
## Parameters:
|
|
428
|
+
n (int|float|Vector2D, optional): The decimal place to round up to. Default is 1.
|
|
429
|
+
|
|
430
|
+
## Returns:
|
|
431
|
+
Vector2D: A new vector with rounded-up components.
|
|
432
|
+
|
|
433
|
+
## Example:
|
|
434
|
+
v = Vector2D(3.14159, 2.71828)
|
|
435
|
+
rounded_v = v.ceil(2)
|
|
436
|
+
print(rounded_v) # Output: (3.15, 2.72)
|
|
437
|
+
|
|
438
|
+
## Explanation:
|
|
439
|
+
This method rounds each component of the vector up to the nearest integer or specified decimal place.
|
|
440
|
+
"""
|
|
261
441
|
...
|
|
262
442
|
|
|
263
443
|
def round(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
|
|
444
|
+
"""
|
|
445
|
+
# Round the Vector2D components to the nearest integer or specified decimal place.
|
|
446
|
+
|
|
447
|
+
## Parameters:
|
|
448
|
+
n (int|float|Vector2D, optional): The decimal place to round to. Default is 1.
|
|
449
|
+
|
|
450
|
+
## Returns:
|
|
451
|
+
Vector2D: A new vector with rounded components.
|
|
452
|
+
|
|
453
|
+
## Example:
|
|
454
|
+
v = Vector2D(3.14159, 2.71828)
|
|
455
|
+
rounded_v = v.round(2)
|
|
456
|
+
print(rounded_v) # Output: (3.14, 2.72)
|
|
457
|
+
|
|
458
|
+
## Explanation:
|
|
459
|
+
This method rounds each component of the vector to the nearest integer or specified decimal place.
|
|
460
|
+
"""
|
|
264
461
|
...
|
|
265
462
|
|
|
266
463
|
@classmethod
|
|
267
|
-
def randomize(cls, start:"int|float|Vector2D", end:"int|float|Vector2D") -> "Vector2D":
|
|
464
|
+
def randomize(cls, start:"int|float|Vector2D", end:"int|float|Vector2D", func:Callable[[int|float], int|float]=lambda val:val) -> "Vector2D":
|
|
268
465
|
"""
|
|
269
466
|
# Generate a random Vector2D point within the specified range.
|
|
270
467
|
|
|
@@ -451,7 +648,65 @@ class Vector2D:
|
|
|
451
648
|
def cartesian_to_complex(self:"Vector2D") -> complex: ...
|
|
452
649
|
|
|
453
650
|
@classmethod
|
|
454
|
-
def complex_to_cartesian(cls, complex_n: complex) -> "Vector2D":
|
|
651
|
+
def complex_to_cartesian(cls, complex_n: complex) -> "Vector2D":
|
|
652
|
+
"""
|
|
653
|
+
# Convert a Complex Number to Cartesian Coordinates
|
|
654
|
+
|
|
655
|
+
## Parameters:
|
|
656
|
+
complex_n (complex): The complex number to convert.
|
|
657
|
+
|
|
658
|
+
## Returns:
|
|
659
|
+
Vector2D: The corresponding (x, y) coordinates as a Vector2D.
|
|
660
|
+
|
|
661
|
+
## Example:
|
|
662
|
+
v = Vector2D.complex_to_cartesian(3 + 4j) # v = Vector2D(3, 4)
|
|
663
|
+
|
|
664
|
+
## Explanation:
|
|
665
|
+
This class method converts a complex number (a + bi) to Cartesian coordinates (x, y).
|
|
666
|
+
The real part 'a' becomes the x-coordinate, and the imaginary part 'b' becomes the y-coordinate.
|
|
667
|
+
"""
|
|
668
|
+
...
|
|
669
|
+
|
|
670
|
+
def cartesian_to_linear(self:"Vector2D", size:int|float) -> int:
|
|
671
|
+
"""
|
|
672
|
+
# Convert 2D Cartesian coordinates to a linear index.
|
|
673
|
+
|
|
674
|
+
## Parameters:
|
|
675
|
+
size (int|float): The width of the grid (number of columns).
|
|
676
|
+
|
|
677
|
+
## Returns:
|
|
678
|
+
int: The linear index corresponding to the (x, y) coordinates.
|
|
679
|
+
|
|
680
|
+
## Example:
|
|
681
|
+
v = Vector2D(3, 2)
|
|
682
|
+
idx = v.cartesian_to_linear(5) # idx = 3 + 2*5 = 13
|
|
683
|
+
|
|
684
|
+
## Explanation:
|
|
685
|
+
This method converts the (x, y) coordinates of the vector to a single linear index,
|
|
686
|
+
assuming row-major order in a 2D grid of the given width.
|
|
687
|
+
"""
|
|
688
|
+
...
|
|
689
|
+
|
|
690
|
+
@classmethod
|
|
691
|
+
def linear_to_cartesian(cls, linear:int, size:int|float) -> "Vector2D":
|
|
692
|
+
"""
|
|
693
|
+
# Convert a linear index to 2D Cartesian coordinates.
|
|
694
|
+
|
|
695
|
+
## Parameters:
|
|
696
|
+
linear (int): The linear index.
|
|
697
|
+
size (int|float): The width of the grid (number of columns).
|
|
698
|
+
|
|
699
|
+
## Returns:
|
|
700
|
+
Vector2D: The corresponding (x, y) coordinates as a Vector2D.
|
|
701
|
+
|
|
702
|
+
## Example:
|
|
703
|
+
v = Vector2D.linear_to_cartesian(13, 5) # v = Vector2D(3, 2)
|
|
704
|
+
|
|
705
|
+
## Explanation:
|
|
706
|
+
This class method converts a linear index to (x, y) coordinates,
|
|
707
|
+
assuming row-major order in a 2D grid of the given width.
|
|
708
|
+
"""
|
|
709
|
+
...
|
|
455
710
|
|
|
456
711
|
def lerp(self:"Vector2D", other:"int|float|Vector2D|list|tuple", t:float=.1) -> "Vector2D":
|
|
457
712
|
"""
|
|
@@ -1046,4 +1301,37 @@ def distance_line_point(line_point_a:Vector2D, line_point_b:Vector2D, point_c:Ve
|
|
|
1046
1301
|
...
|
|
1047
1302
|
|
|
1048
1303
|
def optimize_value_string(value: int|float, precision: int) -> str:
|
|
1304
|
+
"""
|
|
1305
|
+
# Optimize the string representation of a numeric value based on its magnitude and the specified precision.
|
|
1306
|
+
|
|
1307
|
+
## Parameters:
|
|
1308
|
+
value (int | float): The numeric value to be formatted.
|
|
1309
|
+
precision (int): The number of decimal places or significant digits to use in the formatted string.
|
|
1310
|
+
|
|
1311
|
+
## Returns:
|
|
1312
|
+
str: The optimized string representation of the value.
|
|
1313
|
+
|
|
1314
|
+
## Example:
|
|
1315
|
+
value = 0.000012345
|
|
1316
|
+
precision = 3
|
|
1317
|
+
result = optimize_value_string(value, precision)
|
|
1318
|
+
print(result)
|
|
1319
|
+
# Output: '1.235e-05'
|
|
1320
|
+
|
|
1321
|
+
value = 123.456789
|
|
1322
|
+
precision = 2
|
|
1323
|
+
result = optimize_value_string(value, precision)
|
|
1324
|
+
print(result)
|
|
1325
|
+
# Output: '123.46'
|
|
1326
|
+
|
|
1327
|
+
## Explanation:
|
|
1328
|
+
The function formats the input value as a string, choosing between fixed-point and scientific notation
|
|
1329
|
+
based on the magnitude of the value relative to the specified precision:
|
|
1330
|
+
- If the absolute value is very small (less than 1 divided by 10 to the power of precision, but not zero),
|
|
1331
|
+
scientific notation is used.
|
|
1332
|
+
- If the absolute value is less than 10 to the power of precision, fixed-point notation is used,
|
|
1333
|
+
with trailing zeros and decimal points removed for brevity.
|
|
1334
|
+
- Otherwise, scientific notation is used.
|
|
1335
|
+
This ensures that the string representation is concise and readable, while maintaining the requested precision.
|
|
1336
|
+
"""
|
|
1049
1337
|
...
|