e2D 1.4.19__py3-none-any.whl → 1.4.21__py3-none-any.whl

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/__init__.py CHANGED
@@ -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
@@ -34,6 +35,22 @@ 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
46
+
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
37
54
 
38
55
  @property
39
56
  def copy(self) -> "Vector2D":
@@ -42,9 +59,16 @@ class Vector2D:
42
59
  @property
43
60
  def sign(self) -> "Vector2D":
44
61
  return Vector2D(sign(self.x), sign(self.y))
62
+
63
+ def clamp(self, min_val: Vector2D, max_val: Vector2D) -> "Vector2D":
64
+ return Vector2D(clamp(self.x, min_val.x, max_val.x), clamp(self.y, min_val.y, max_val.y))
65
+
66
+ def iclamp(self, min_val: Vector2D, max_val: Vector2D) -> None:
67
+ self.x = clamp(self.x, min_val.x, max_val.x)
68
+ self.y = clamp(self.y, min_val.y, max_val.y)
45
69
 
46
70
  @property
47
- def normalize(self) -> "Vector2D":
71
+ def normalized(self) -> "Vector2D":
48
72
  if (mag:=self.length) == 0:
49
73
  return self.copy
50
74
  return Vector2D(self.x / mag, self.y / mag)
@@ -52,11 +76,31 @@ class Vector2D:
52
76
  @property
53
77
  def length(self) -> float:
54
78
  return (self.x ** 2 + self.y ** 2) ** .5
55
-
79
+
80
+ @length.setter
81
+ def length(self, new_length: float) -> None:
82
+ current_length = self.length
83
+ if current_length == 0:
84
+ self.x = new_length
85
+ self.y = 0
86
+ else:
87
+ self.x *= new_length / current_length
88
+ self.y *= new_length / current_length
89
+
56
90
  @property
57
91
  def length_sqrd(self) -> float:
58
92
  return self.x ** 2 + self.y ** 2
59
-
93
+
94
+ @length_sqrd.setter
95
+ def length_sqrd(self, new_length_sqrd: float) -> None:
96
+ current_length = self.length
97
+ if current_length == 0:
98
+ self.x = _mt.sqrt(new_length_sqrd)
99
+ self.y = 0
100
+ else:
101
+ self.x *= _mt.sqrt(new_length_sqrd) / current_length
102
+ self.y *= _mt.sqrt(new_length_sqrd) / current_length
103
+
60
104
  @property
61
105
  def inverse(self) -> "Vector2D":
62
106
  return self.mult(-1)
@@ -111,6 +155,13 @@ class Vector2D:
111
155
  def complex_to_cartesian(cls, complex_n) -> "Vector2D":
112
156
  return cls(complex_n.real, complex_n.imag)
113
157
 
158
+ def cartesian_to_linear(self, size) -> int:
159
+ return int(self.x + self.y * size)
160
+
161
+ @classmethod
162
+ def linear_to_cartesian(cls, linear, size) -> "Vector2D":
163
+ return cls(linear % size, linear // size)
164
+
114
165
  def lerp(self, other, t=.1) -> "Vector2D":
115
166
  return Vector2D(self.x + (other.x - self.x) * t, self.y + (other.y - self.y) * t)
116
167
 
@@ -487,10 +538,10 @@ V2down_right = Vector2D(1, -1)
487
538
  V2up_left = Vector2D(-1, 1)
488
539
  V2down_left = Vector2D(-1, -1)
489
540
 
490
- V2up_right_norm = V2up_right.normalize
491
- V2down_right_norm = V2down_right.normalize
492
- V2up_left_norm = V2up_left.normalize
493
- V2down_left_norm = V2down_left.normalize
541
+ V2up_right_norm = V2up_right.normalized
542
+ V2down_right_norm = V2down_right.normalized
543
+ V2up_left_norm = V2up_left.normalized
544
+ V2down_left_norm = V2down_left.normalized
494
545
 
495
546
  VECTORS_4_DIRECTIONS = (V2right, V2down, V2left, V2up)
496
547
  VECTORS_4_SEMIDIRECTIONS = (V2down_right, V2down_left, V2up_left, V2up_right)
e2D/__init__.pyi CHANGED
@@ -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
@@ -140,10 +141,59 @@ 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: ...
179
+
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: ...
147
197
 
148
198
  @property
149
199
  def copy(self:"Vector2D") -> "Vector2D":
@@ -211,8 +261,56 @@ class Vector2D:
211
261
  """
212
262
  ...
213
263
 
264
+ def clamp(self, min_val: Vector2D, max_val: Vector2D) -> "Vector2D":
265
+ """
266
+ # Clamp the vector's components between the corresponding components of two other vectors.
267
+
268
+ ## Parameters:
269
+ min_val (Vector2D): The minimum vector for clamping.
270
+ max_val (Vector2D): The maximum vector for clamping.
271
+
272
+ ## Returns:
273
+ Vector2D: A new vector with its components clamped between the corresponding components of `min_val` and `max_val`.
274
+
275
+ ## Example:
276
+ v = Vector2D(5, 10)
277
+ min_val = Vector2D(0, 8)
278
+ max_val = Vector2D(6, 12)
279
+ clamped_v = v.clamp(min_val, max_val)
280
+ print(clamped_v) # Output: (5, 10)
281
+
282
+ ## Explanation:
283
+ This method clamps the x and y components of the current vector between the corresponding x and y components
284
+ of the `min_val` and `max_val` vectors. The resulting vector is returned as a new Vector2D instance.
285
+ """
286
+ ...
287
+
288
+ def iclamp(self, min_val: Vector2D, max_val: Vector2D) -> None:
289
+ """
290
+ # Clamp the vector's components in place between the corresponding components of two other vectors.
291
+
292
+ ## Parameters:
293
+ min_val (Vector2D): The minimum vector for clamping.
294
+ max_val (Vector2D): The maximum vector for clamping.
295
+
296
+ ## Returns:
297
+ None
298
+
299
+ ## Example:
300
+ v = Vector2D(5, 10)
301
+ min_val = Vector2D(0, 8)
302
+ max_val = Vector2D(6, 12)
303
+ v.iclamp(min_val, max_val)
304
+ print(v) # Output: (5, 10)
305
+
306
+ ## Explanation:
307
+ This method clamps the x and y components of the current vector in place between the corresponding x and y components
308
+ of the `min_val` and `max_val` vectors. The method modifies the current vector directly.
309
+ """
310
+ ...
311
+
214
312
  @property
215
- def normalize(self:"Vector2D") -> "Vector2D":
313
+ def normalized(self:"Vector2D") -> "Vector2D":
216
314
  """
217
315
  # Vector Normalization
218
316
 
@@ -224,7 +322,7 @@ class Vector2D:
224
322
 
225
323
  ## Example:
226
324
  v = Vector2D(3, 4)
227
- normalized_v = v.normalize() # Normalize the vector (3, 4)
325
+ normalized_v = v.normalized() # Normalize the vector (3, 4)
228
326
  print(normalized_v) # Output: (0.6, 0.8)
229
327
 
230
328
  ## Explanation:
@@ -244,23 +342,123 @@ class Vector2D:
244
342
 
245
343
  @property
246
344
  def length(self:"Vector2D") -> float:
345
+ """
346
+ # Vector Length
347
+
348
+ ## Returns:
349
+ float: The length (magnitude) of the vector.
350
+
351
+ ## Example:
352
+ v = Vector2D(3, 4)
353
+ length = v.length
354
+ print(length) # Output: 5.0
355
+
356
+ ## Explanation:
357
+ This property calculates the length (magnitude) of the vector using the Pythagorean theorem.
358
+ """
247
359
  ...
248
360
 
249
361
  @property
250
362
  def length_sqrd(self:"Vector2D") -> float:
363
+ """
364
+ # Vector Length Squared
365
+
366
+ ## Returns:
367
+ float: The squared length (magnitude) of the vector.
368
+
369
+ ## Example:
370
+ v = Vector2D(3, 4)
371
+ length_sqrd = v.length_sqrd
372
+ print(length_sqrd) # Output: 25
373
+
374
+ ## Explanation:
375
+ This property calculates the squared length (magnitude) of the vector.
376
+ It is more efficient than calculating the actual length, as it avoids the
377
+ square root calculation.
378
+ """
251
379
  ...
252
380
 
253
381
  @property
254
382
  def inverse(self:"Vector2D") -> "Vector2D":
383
+ """
384
+ # Vector Inversion
385
+
386
+ ## Returns:
387
+ Vector2D: A new vector with inverted components.
388
+
389
+ ## Example:
390
+ v = Vector2D(3, 4)
391
+ inverted_v = v.inverse()
392
+ print(inverted_v) # Output: (-3, -4)
393
+
394
+ ## Explanation:
395
+ This method calculates the inverted version of the current vector, which means a new vector with the same magnitude
396
+ but opposite direction.
397
+
398
+ The inverted vector is obtained by negating each component of the current vector.
399
+
400
+ The resulting inverted vector is returned.
401
+ """
255
402
  ...
256
403
 
257
404
  def floor(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
405
+ """
406
+ # Round the Vector2D components down to the nearest integer or specified decimal place.
407
+
408
+ ## Parameters:
409
+ n (int|float|Vector2D, optional): The decimal place to round down to. Default is 1.
410
+
411
+ ## Returns:
412
+ Vector2D: A new vector with rounded-down components.
413
+
414
+ ## Example:
415
+ v = Vector2D(3.14159, 2.71828)
416
+ rounded_v = v.floor(2)
417
+ print(rounded_v) # Output: (3.14, 2.71)
418
+
419
+ ## Explanation:
420
+ This method rounds each component of the vector down to the nearest integer or specified decimal place.
421
+ """
258
422
  ...
259
423
 
260
424
  def ceil(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
425
+ """
426
+ # Round the Vector2D components up to the nearest integer or specified decimal place.
427
+
428
+ ## Parameters:
429
+ n (int|float|Vector2D, optional): The decimal place to round up to. Default is 1.
430
+
431
+ ## Returns:
432
+ Vector2D: A new vector with rounded-up components.
433
+
434
+ ## Example:
435
+ v = Vector2D(3.14159, 2.71828)
436
+ rounded_v = v.ceil(2)
437
+ print(rounded_v) # Output: (3.15, 2.72)
438
+
439
+ ## Explanation:
440
+ This method rounds each component of the vector up to the nearest integer or specified decimal place.
441
+ """
261
442
  ...
262
443
 
263
444
  def round(self:"Vector2D", n:"int|float|Vector2D"=1) -> "Vector2D":
445
+ """
446
+ # Round the Vector2D components to the nearest integer or specified decimal place.
447
+
448
+ ## Parameters:
449
+ n (int|float|Vector2D, optional): The decimal place to round to. Default is 1.
450
+
451
+ ## Returns:
452
+ Vector2D: A new vector with rounded components.
453
+
454
+ ## Example:
455
+ v = Vector2D(3.14159, 2.71828)
456
+ rounded_v = v.round(2)
457
+ print(rounded_v) # Output: (3.14, 2.72)
458
+
459
+ ## Explanation:
460
+ This method rounds each component of the vector to the nearest integer or specified decimal place.
461
+ """
264
462
  ...
265
463
 
266
464
  @classmethod
@@ -451,7 +649,65 @@ class Vector2D:
451
649
  def cartesian_to_complex(self:"Vector2D") -> complex: ...
452
650
 
453
651
  @classmethod
454
- def complex_to_cartesian(cls, complex_n: complex) -> "Vector2D": ...
652
+ def complex_to_cartesian(cls, complex_n: complex) -> "Vector2D":
653
+ """
654
+ # Convert a Complex Number to Cartesian Coordinates
655
+
656
+ ## Parameters:
657
+ complex_n (complex): The complex number to convert.
658
+
659
+ ## Returns:
660
+ Vector2D: The corresponding (x, y) coordinates as a Vector2D.
661
+
662
+ ## Example:
663
+ v = Vector2D.complex_to_cartesian(3 + 4j) # v = Vector2D(3, 4)
664
+
665
+ ## Explanation:
666
+ This class method converts a complex number (a + bi) to Cartesian coordinates (x, y).
667
+ The real part 'a' becomes the x-coordinate, and the imaginary part 'b' becomes the y-coordinate.
668
+ """
669
+ ...
670
+
671
+ def cartesian_to_linear(self:"Vector2D", size:int|float) -> int:
672
+ """
673
+ # Convert 2D Cartesian coordinates to a linear index.
674
+
675
+ ## Parameters:
676
+ size (int|float): The width of the grid (number of columns).
677
+
678
+ ## Returns:
679
+ int: The linear index corresponding to the (x, y) coordinates.
680
+
681
+ ## Example:
682
+ v = Vector2D(3, 2)
683
+ idx = v.cartesian_to_linear(5) # idx = 3 + 2*5 = 13
684
+
685
+ ## Explanation:
686
+ This method converts the (x, y) coordinates of the vector to a single linear index,
687
+ assuming row-major order in a 2D grid of the given width.
688
+ """
689
+ ...
690
+
691
+ @classmethod
692
+ def linear_to_cartesian(cls, linear:int, size:int|float) -> "Vector2D":
693
+ """
694
+ # Convert a linear index to 2D Cartesian coordinates.
695
+
696
+ ## Parameters:
697
+ linear (int): The linear index.
698
+ size (int|float): The width of the grid (number of columns).
699
+
700
+ ## Returns:
701
+ Vector2D: The corresponding (x, y) coordinates as a Vector2D.
702
+
703
+ ## Example:
704
+ v = Vector2D.linear_to_cartesian(13, 5) # v = Vector2D(3, 2)
705
+
706
+ ## Explanation:
707
+ This class method converts a linear index to (x, y) coordinates,
708
+ assuming row-major order in a 2D grid of the given width.
709
+ """
710
+ ...
455
711
 
456
712
  def lerp(self:"Vector2D", other:"int|float|Vector2D|list|tuple", t:float=.1) -> "Vector2D":
457
713
  """
@@ -1046,4 +1302,37 @@ def distance_line_point(line_point_a:Vector2D, line_point_b:Vector2D, point_c:Ve
1046
1302
  ...
1047
1303
 
1048
1304
  def optimize_value_string(value: int|float, precision: int) -> str:
1305
+ """
1306
+ # Optimize the string representation of a numeric value based on its magnitude and the specified precision.
1307
+
1308
+ ## Parameters:
1309
+ value (int | float): The numeric value to be formatted.
1310
+ precision (int): The number of decimal places or significant digits to use in the formatted string.
1311
+
1312
+ ## Returns:
1313
+ str: The optimized string representation of the value.
1314
+
1315
+ ## Example:
1316
+ value = 0.000012345
1317
+ precision = 3
1318
+ result = optimize_value_string(value, precision)
1319
+ print(result)
1320
+ # Output: '1.235e-05'
1321
+
1322
+ value = 123.456789
1323
+ precision = 2
1324
+ result = optimize_value_string(value, precision)
1325
+ print(result)
1326
+ # Output: '123.46'
1327
+
1328
+ ## Explanation:
1329
+ The function formats the input value as a string, choosing between fixed-point and scientific notation
1330
+ based on the magnitude of the value relative to the specified precision:
1331
+ - If the absolute value is very small (less than 1 divided by 10 to the power of precision, but not zero),
1332
+ scientific notation is used.
1333
+ - If the absolute value is less than 10 to the power of precision, fixed-point notation is used,
1334
+ with trailing zeros and decimal points removed for brevity.
1335
+ - Otherwise, scientific notation is used.
1336
+ This ensures that the string representation is concise and readable, while maintaining the requested precision.
1337
+ """
1049
1338
  ...
e2D/colors.py CHANGED
@@ -1,7 +1,8 @@
1
+ from __future__ import annotations
1
2
  from colorsys import hsv_to_rgb as __hsv_to_rgb_def__, hls_to_rgb as __hls_to_rgb_def__, rgb_to_hls as __rgb_to_hls__, rgb_to_hsv as __rgb_to_hsv__
2
3
  from typing import Any, Callable, Generator, Literal
3
4
  from pygame.color import Color as __color_pygame__
4
- from random import randint as __randint__
5
+ from random import random as __rand__
5
6
 
6
7
  RGB_COLOR_MODE = "rgb"
7
8
  RGBA_COLOR_MODE = "rgba"
@@ -15,11 +16,11 @@ HLS_COLOR_MODE = "hls"
15
16
 
16
17
  __LITERAL_COLOR_MODES__ = Literal["rgb","rgba","bgr","bgra","g","hsv","hls"] #,"cmyk","lab"]
17
18
 
18
- def __hsv_to_rgb__(h:int|float, s:int|float, v:int|float) -> tuple[int|float, int|float, int|float]:
19
+ def __hsv_to_rgb__(h:"int|float", s:"int|float", v:"int|float") -> tuple["int|float", "int|float", "int|float"]:
19
20
  r,g,b = __hsv_to_rgb_def__(h, s, v)
20
21
  return r*255, g*255, b*255
21
22
 
22
- def __hls_to_rgb__(h:int|float, s:int|float, v:int|float) -> tuple[int|float, int|float, int|float]:
23
+ def __hls_to_rgb__(h:"int|float", s:"int|float", v:"int|float") -> tuple["int|float", "int|float", "int|float"]:
23
24
  r,g,b = __hls_to_rgb_def__(h, s, v)
24
25
  return r*255, g*255, b*255
25
26
 
@@ -82,6 +83,12 @@ __conversion_table__ :dict[__LITERAL_COLOR_MODES__, dict[__LITERAL_COLOR_MODES__
82
83
  },
83
84
  }
84
85
 
86
+ def pygamize_color(color: "__color_pygame__|Color") -> "__color_pygame__":
87
+ return color() if isinstance(color, Color) else color
88
+
89
+ def unpygamize_color(color: "__color_pygame__|Color") -> "Color":
90
+ return Color(*color[:], mode=RGBA_COLOR_MODE) if isinstance(color, __color_pygame__) else color
91
+
85
92
  class Color:
86
93
  def __init__(self, *values, mode:__LITERAL_COLOR_MODES__=RGB_COLOR_MODE) -> None:
87
94
  self.__dict__ = dict(zip(mode, values))
@@ -104,35 +111,35 @@ class Color:
104
111
  return (d ** .5) if rooted else d
105
112
 
106
113
  @classmethod
107
- def new_rgb(cls, r:int|float, g:int|float, b:int|float) -> "Color":
114
+ def new_rgb(cls, r:"int|float", g:"int|float", b:"int|float") -> "Color":
108
115
  return Color(r,g,b, mode=RGB_COLOR_MODE)
109
116
  @classmethod
110
- def new_rgba(cls, r:int|float, g:int|float, b:int|float, a:int|float) -> "Color":
117
+ def new_rgba(cls, r:"int|float", g:"int|float", b:"int|float", a:"int|float") -> "Color":
111
118
  return Color(r,g,b,a, mode=RGBA_COLOR_MODE)
112
119
  @classmethod
113
- def new_bgr(cls, b:int|float, g:int|float, r:int|float) -> "Color":
120
+ def new_bgr(cls, b:"int|float", g:"int|float", r:"int|float") -> "Color":
114
121
  return Color(b,g,r, mode=BGR_COLOR_MODE)
115
122
  @classmethod
116
- def new_bgra(cls, b:int|float, g:int|float, r:int|float, a:int|float) -> "Color":
123
+ def new_bgra(cls, b:"int|float", g:"int|float", r:"int|float", a:"int|float") -> "Color":
117
124
  return Color(b,g,r,a, mode=BGRA_COLOR_MODE)
118
125
  @classmethod
119
126
  def new_g(cls, g) -> "Color":
120
127
  return Color(g, mode=GRAY_COLOR_MODE)
121
128
  @classmethod
122
- def new_hsv(cls, h:int|float, s:int|float, v:int|float) -> "Color":
129
+ def new_hsv(cls, h:"int|float", s:"int|float", v:"int|float") -> "Color":
123
130
  return Color(h,s,v, mode=HSV_COLOR_MODE)
124
131
  @classmethod
125
- def new_hls(cls, h:int|float, l:int|float, s:int|float) -> "Color":
132
+ def new_hls(cls, h:"int|float", l:"int|float", s:"int|float") -> "Color":
126
133
  return Color(h,l,s, mode=HLS_COLOR_MODE)
127
134
  # @classmethod
128
- # def new_cmyk(cls, c:int|float, m:int|float, y:int|float, k:int|float) -> Color:
135
+ # def new_cmyk(cls, c:"int|float", m:"int|float", y:"int|float", k:"int|float") -> Color:
129
136
  # return Color(c,m,y,k, mode=CMYK_COLOR_MODE)
130
137
  # @classmethod
131
- # def new_lab(cls, l:int|float, a:int|float, b:int|float) -> Color:
138
+ # def new_lab(cls, l:"int|float", a:"int|float", b:"int|float") -> Color:
132
139
  # return Color(l,a,b, mode=LAB_COLOR_MODE)
133
140
 
134
141
  @property
135
- def values(self) -> tuple[int|float, ...]:
142
+ def values(self) -> tuple["int|float", ...]:
136
143
  return tuple(self.__dict__.values())[:-1]
137
144
 
138
145
  @property
@@ -140,7 +147,7 @@ class Color:
140
147
  return tuple(self.__dict__.keys())[:-1]
141
148
 
142
149
  @property
143
- def items(self) -> tuple[tuple[str, int|float], ...]:
150
+ def items(self) -> tuple[tuple[str, "int|float"], ...]:
144
151
  return tuple(self.__dict__.items())[:-1]
145
152
 
146
153
  def copy(self) -> "Color":
@@ -179,7 +186,7 @@ class Color:
179
186
  return "Color(" + ", ".join(f"{k}:{v}" for k, v in self.items) + ")"
180
187
 
181
188
  def __call__(self) -> __color_pygame__:
182
- return __color_pygame__(int(self.r), int(self.g), int(self.b))
189
+ return __color_pygame__(int(self.r), int(self.g), int(self.b)) if self.mode == RGB_COLOR_MODE else __color_pygame__(int(self.r), int(self.g), int(self.b), int(self.a))
183
190
 
184
191
  # fast operations Vector2D.operation(both,x,y)
185
192
  def add(self, all3=.0, r=.0, g=.0, b=.0) -> "Color":
@@ -386,7 +393,7 @@ class Color:
386
393
  def __float__(self) -> "Color":
387
394
  return Color(float(self.r), float(self.g), float(self.b))
388
395
 
389
- def __getitem__(self, n) -> int|float:
396
+ def __getitem__(self, n) -> "int|float":
390
397
  return self.values[n] if isinstance(n, int) else self.values[self.keys.index(n)]
391
398
 
392
399
  def __iter__(self) -> Generator[float, Any, None]:
@@ -406,8 +413,10 @@ class Color:
406
413
  try:
407
414
  return cls(*other.values, mode=other.mode)
408
415
  except:
409
- raise TypeError(f"The value {other} of type {type(other)} is not a num type: [{int|float}] nor an array type: [{list|tuple}]")
416
+ raise TypeError(f"The value {other} of type {type(other)} is not a num type: [{"int|float"}] nor an array type: [{list|tuple}]")
410
417
 
418
+ @classmethod
419
+ def transparent(cls) -> "Color": return Color(0,0,0,0, mode=RGBA_COLOR_MODE)
411
420
  @classmethod
412
421
  def white(cls) -> "Color": return Color(255,255,255)
413
422
  @classmethod
@@ -418,23 +427,44 @@ class Color:
418
427
  def green(cls) -> "Color": return Color(0,255,0)
419
428
  @classmethod
420
429
  def blue(cls) -> "Color": return Color(0,0,255)
421
-
422
- # @classmethod
423
- # def (cls) -> "Color": return Color(0,0,255)
424
-
425
430
  @classmethod
426
- def randomize(cls) -> "Color":
427
- return Color(__randint__(0,255), __randint__(0,255), __randint__(0,255))
428
-
431
+ def cyan(cls) -> "Color": return Color(0,255,255)
432
+ @classmethod
433
+ def magenta(cls) -> "Color": return Color(255,0,255)
434
+ @classmethod
435
+ def yellow(cls) -> "Color": return Color(255,255,0)
429
436
 
437
+ @classmethod
438
+ def randomize(cls, start=0, end=255, func=lambda val:val) -> "Color":
439
+ if not isinstance(start, Color):
440
+ if isinstance(start, (int, float)):
441
+ start = Color(start, start, start)
442
+ else:
443
+ raise Exception(f"\nArg start must be in [Color, int, float, tuple, list] not a [{type(start)}]\n")
444
+ if not isinstance(end, Color):
445
+ if isinstance(end, (int, float)):
446
+ end = Color(end, end, end)
447
+ else:
448
+ raise Exception(f"\nArg end must be in [Color, int, float, tuple, list] not a [{type(end)}]\n")
449
+ return start + Color(func(__rand__()), func(__rand__()), func(__rand__())) * (end - start)
450
+
451
+
452
+ TRANSPARENT_COLOR = Color.transparent()
430
453
  WHITE_COLOR = Color.white()
431
454
  BLACK_COLOR = Color.black()
432
455
  RED_COLOR = Color.red()
433
456
  GREEN_COLOR = Color.green()
434
457
  BLUE_COLOR = Color.blue()
458
+ CYAN_COLOR = Color.cyan()
459
+ MAGENTA_COLOR = Color.magenta()
460
+ YELLOW_COLOR = Color.yellow()
435
461
 
462
+ TRANSPARENT_COLOR_PYG = TRANSPARENT_COLOR()
436
463
  WHITE_COLOR_PYG = WHITE_COLOR()
437
464
  BLACK_COLOR_PYG = BLACK_COLOR()
438
465
  RED_COLOR_PYG = RED_COLOR()
439
466
  GREEN_COLOR_PYG = GREEN_COLOR()
440
467
  BLUE_COLOR_PYG = BLUE_COLOR()
468
+ CYAN_COLOR_PYG = CYAN_COLOR()
469
+ MAGENTA_COLOR_PYG = MAGENTA_COLOR()
470
+ YELLOW_COLOR_PYG = YELLOW_COLOR()