e2D 1.4.20__py3-none-any.whl → 1.4.24__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
@@ -35,8 +35,23 @@ class Vector2D:
35
35
  @angle.setter
36
36
  def angle(self, new_angle) -> None:
37
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
38
46
 
39
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
+
40
55
  def copy(self) -> "Vector2D":
41
56
  return Vector2D(self.x, self.y)
42
57
 
@@ -52,19 +67,39 @@ class Vector2D:
52
67
  self.y = clamp(self.y, min_val.y, max_val.y)
53
68
 
54
69
  @property
55
- def normalize(self) -> "Vector2D":
70
+ def normalized(self) -> "Vector2D":
56
71
  if (mag:=self.length) == 0:
57
- return self.copy
72
+ return self.copy()
58
73
  return Vector2D(self.x / mag, self.y / mag)
59
74
 
60
75
  @property
61
76
  def length(self) -> float:
62
77
  return (self.x ** 2 + self.y ** 2) ** .5
63
-
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
+
64
89
  @property
65
90
  def length_sqrd(self) -> float:
66
91
  return self.x ** 2 + self.y ** 2
67
-
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
+
68
103
  @property
69
104
  def inverse(self) -> "Vector2D":
70
105
  return self.mult(-1)
@@ -119,6 +154,13 @@ class Vector2D:
119
154
  def complex_to_cartesian(cls, complex_n) -> "Vector2D":
120
155
  return cls(complex_n.real, complex_n.imag)
121
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
+
122
164
  def lerp(self, other, t=.1) -> "Vector2D":
123
165
  return Vector2D(self.x + (other.x - self.x) * t, self.y + (other.y - self.y) * t)
124
166
 
@@ -428,47 +470,47 @@ class Vector2D:
428
470
  def down_left_norm(cls) -> "Vector2D": return V2down_left_norm
429
471
 
430
472
  @classmethod
431
- def new_zero(cls) -> "Vector2D": return V2zero.copy
473
+ def new_zero(cls) -> "Vector2D": return V2zero.copy()
432
474
  @classmethod
433
- def new_one(cls) -> "Vector2D": return V2one.copy
475
+ def new_one(cls) -> "Vector2D": return V2one.copy()
434
476
  @classmethod
435
- def new_two(cls) -> "Vector2D": return V2two.copy
477
+ def new_two(cls) -> "Vector2D": return V2two.copy()
436
478
  @classmethod
437
- def new_pi(cls) -> "Vector2D": return V2pi.copy
479
+ def new_pi(cls) -> "Vector2D": return V2pi.copy()
438
480
  @classmethod
439
- def new_inf(cls) -> "Vector2D": return V2inf.copy
481
+ def new_inf(cls) -> "Vector2D": return V2inf.copy()
440
482
  @classmethod
441
- def new_neg_one(cls) -> "Vector2D": return V2neg_one.copy
483
+ def new_neg_one(cls) -> "Vector2D": return V2neg_one.copy()
442
484
  @classmethod
443
- def new_neg_two(cls) -> "Vector2D": return V2neg_two.copy
485
+ def new_neg_two(cls) -> "Vector2D": return V2neg_two.copy()
444
486
  @classmethod
445
- def new_neg_pi(cls) -> "Vector2D": return V2neg_pi.copy
487
+ def new_neg_pi(cls) -> "Vector2D": return V2neg_pi.copy()
446
488
  @classmethod
447
- def new_neg_inf(cls) -> "Vector2D": return V2neg_inf.copy
489
+ def new_neg_inf(cls) -> "Vector2D": return V2neg_inf.copy()
448
490
  @classmethod
449
- def new_up(cls) -> "Vector2D": return V2up.copy
491
+ def new_up(cls) -> "Vector2D": return V2up.copy()
450
492
  @classmethod
451
- def new_right(cls) -> "Vector2D": return V2right.copy
493
+ def new_right(cls) -> "Vector2D": return V2right.copy()
452
494
  @classmethod
453
- def new_down(cls) -> "Vector2D": return V2down.copy
495
+ def new_down(cls) -> "Vector2D": return V2down.copy()
454
496
  @classmethod
455
- def new_left(cls) -> "Vector2D": return V2left.copy
497
+ def new_left(cls) -> "Vector2D": return V2left.copy()
456
498
  @classmethod
457
- def new_up_right(cls) -> "Vector2D": return V2up_right.copy
499
+ def new_up_right(cls) -> "Vector2D": return V2up_right.copy()
458
500
  @classmethod
459
- def new_down_right(cls) -> "Vector2D": return V2down_right.copy
501
+ def new_down_right(cls) -> "Vector2D": return V2down_right.copy()
460
502
  @classmethod
461
- def new_up_left(cls) -> "Vector2D": return V2up_left.copy
503
+ def new_up_left(cls) -> "Vector2D": return V2up_left.copy()
462
504
  @classmethod
463
- def new_down_left(cls) -> "Vector2D": return V2down_left.copy
505
+ def new_down_left(cls) -> "Vector2D": return V2down_left.copy()
464
506
  @classmethod
465
- 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()
466
508
  @classmethod
467
- 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()
468
510
  @classmethod
469
- 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()
470
512
  @classmethod
471
- 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()
472
514
 
473
515
 
474
516
  V2 = Vector2D
@@ -495,10 +537,10 @@ V2down_right = Vector2D(1, -1)
495
537
  V2up_left = Vector2D(-1, 1)
496
538
  V2down_left = Vector2D(-1, -1)
497
539
 
498
- V2up_right_norm = V2up_right.normalize
499
- V2down_right_norm = V2down_right.normalize
500
- V2up_left_norm = V2up_left.normalize
501
- V2down_left_norm = V2down_left.normalize
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
502
544
 
503
545
  VECTORS_4_DIRECTIONS = (V2right, V2down, V2left, V2up)
504
546
  VECTORS_4_SEMIDIRECTIONS = (V2down_right, V2down_left, V2up_left, V2up_right)
e2D/__init__.pyi CHANGED
@@ -141,12 +141,60 @@ class Vector2D:
141
141
  ...
142
142
 
143
143
  @property
144
- 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
+ ...
145
157
 
146
158
  @angle.setter
147
- def angle(self:"Vector2D", argv) -> None: ...
159
+ def angle(self:"Vector2D", argv) -> None:
160
+ ...
148
161
 
149
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: ...
197
+
150
198
  def copy(self:"Vector2D") -> "Vector2D":
151
199
  """
152
200
  # Create a copy of the current Vector2D other.
@@ -261,7 +309,7 @@ class Vector2D:
261
309
  ...
262
310
 
263
311
  @property
264
- def normalize(self:"Vector2D") -> "Vector2D":
312
+ def normalized(self:"Vector2D") -> "Vector2D":
265
313
  """
266
314
  # Vector Normalization
267
315
 
@@ -273,7 +321,7 @@ class Vector2D:
273
321
 
274
322
  ## Example:
275
323
  v = Vector2D(3, 4)
276
- normalized_v = v.normalize() # Normalize the vector (3, 4)
324
+ normalized_v = v.normalized() # Normalize the vector (3, 4)
277
325
  print(normalized_v) # Output: (0.6, 0.8)
278
326
 
279
327
  ## Explanation:
@@ -293,23 +341,123 @@ class Vector2D:
293
341
 
294
342
  @property
295
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
+ """
296
358
  ...
297
359
 
298
360
  @property
299
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
+ """
300
378
  ...
301
379
 
302
380
  @property
303
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
+ """
304
401
  ...
305
402
 
306
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
+ """
307
421
  ...
308
422
 
309
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
+ """
310
441
  ...
311
442
 
312
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
+ """
313
461
  ...
314
462
 
315
463
  @classmethod
@@ -500,7 +648,65 @@ class Vector2D:
500
648
  def cartesian_to_complex(self:"Vector2D") -> complex: ...
501
649
 
502
650
  @classmethod
503
- 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
+ ...
504
710
 
505
711
  def lerp(self:"Vector2D", other:"int|float|Vector2D|list|tuple", t:float=.1) -> "Vector2D":
506
712
  """
@@ -1095,4 +1301,37 @@ def distance_line_point(line_point_a:Vector2D, line_point_b:Vector2D, point_c:Ve
1095
1301
  ...
1096
1302
 
1097
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
+ """
1098
1337
  ...
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
 
@@ -110,35 +111,35 @@ class Color:
110
111
  return (d ** .5) if rooted else d
111
112
 
112
113
  @classmethod
113
- 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":
114
115
  return Color(r,g,b, mode=RGB_COLOR_MODE)
115
116
  @classmethod
116
- 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":
117
118
  return Color(r,g,b,a, mode=RGBA_COLOR_MODE)
118
119
  @classmethod
119
- 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":
120
121
  return Color(b,g,r, mode=BGR_COLOR_MODE)
121
122
  @classmethod
122
- 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":
123
124
  return Color(b,g,r,a, mode=BGRA_COLOR_MODE)
124
125
  @classmethod
125
126
  def new_g(cls, g) -> "Color":
126
127
  return Color(g, mode=GRAY_COLOR_MODE)
127
128
  @classmethod
128
- 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":
129
130
  return Color(h,s,v, mode=HSV_COLOR_MODE)
130
131
  @classmethod
131
- 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":
132
133
  return Color(h,l,s, mode=HLS_COLOR_MODE)
133
134
  # @classmethod
134
- # 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:
135
136
  # return Color(c,m,y,k, mode=CMYK_COLOR_MODE)
136
137
  # @classmethod
137
- # 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:
138
139
  # return Color(l,a,b, mode=LAB_COLOR_MODE)
139
140
 
140
141
  @property
141
- def values(self) -> tuple[int|float, ...]:
142
+ def values(self) -> tuple["int|float", ...]:
142
143
  return tuple(self.__dict__.values())[:-1]
143
144
 
144
145
  @property
@@ -146,7 +147,7 @@ class Color:
146
147
  return tuple(self.__dict__.keys())[:-1]
147
148
 
148
149
  @property
149
- def items(self) -> tuple[tuple[str, int|float], ...]:
150
+ def items(self) -> tuple[tuple[str, "int|float"], ...]:
150
151
  return tuple(self.__dict__.items())[:-1]
151
152
 
152
153
  def copy(self) -> "Color":
@@ -392,7 +393,7 @@ class Color:
392
393
  def __float__(self) -> "Color":
393
394
  return Color(float(self.r), float(self.g), float(self.b))
394
395
 
395
- def __getitem__(self, n) -> int|float:
396
+ def __getitem__(self, n) -> "int|float":
396
397
  return self.values[n] if isinstance(n, int) else self.values[self.keys.index(n)]
397
398
 
398
399
  def __iter__(self) -> Generator[float, Any, None]:
@@ -412,7 +413,7 @@ class Color:
412
413
  try:
413
414
  return cls(*other.values, mode=other.mode)
414
415
  except:
415
- 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]")
416
417
 
417
418
  @classmethod
418
419
  def transparent(cls) -> "Color": return Color(0,0,0,0, mode=RGBA_COLOR_MODE)
@@ -426,13 +427,26 @@ class Color:
426
427
  def green(cls) -> "Color": return Color(0,255,0)
427
428
  @classmethod
428
429
  def blue(cls) -> "Color": return Color(0,0,255)
429
-
430
- # @classmethod
431
- # def (cls) -> "Color": return Color(0,0,255)
430
+ @classmethod
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)
432
436
 
433
437
  @classmethod
434
- def randomize(cls) -> "Color":
435
- return Color(__randint__(0,255), __randint__(0,255), __randint__(0,255))
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)
436
450
 
437
451
 
438
452
  TRANSPARENT_COLOR = Color.transparent()
@@ -441,6 +455,9 @@ BLACK_COLOR = Color.black()
441
455
  RED_COLOR = Color.red()
442
456
  GREEN_COLOR = Color.green()
443
457
  BLUE_COLOR = Color.blue()
458
+ CYAN_COLOR = Color.cyan()
459
+ MAGENTA_COLOR = Color.magenta()
460
+ YELLOW_COLOR = Color.yellow()
444
461
 
445
462
  TRANSPARENT_COLOR_PYG = TRANSPARENT_COLOR()
446
463
  WHITE_COLOR_PYG = WHITE_COLOR()
@@ -448,3 +465,6 @@ BLACK_COLOR_PYG = BLACK_COLOR()
448
465
  RED_COLOR_PYG = RED_COLOR()
449
466
  GREEN_COLOR_PYG = GREEN_COLOR()
450
467
  BLUE_COLOR_PYG = BLUE_COLOR()
468
+ CYAN_COLOR_PYG = CYAN_COLOR()
469
+ MAGENTA_COLOR_PYG = MAGENTA_COLOR()
470
+ YELLOW_COLOR_PYG = YELLOW_COLOR()