e2D 1.3.9__py3-none-any.whl → 1.3.11__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
@@ -15,7 +15,7 @@ DOUBLE_PI = PI*2
15
15
  #
16
16
 
17
17
  class Vector2D:
18
- round_values_on_print :float= 1.0
18
+ round_values_on_print :int|float= 2
19
19
  def __init__(self:"V2|Vector2D", x:int|float=0.0, y:int|float=0.0) -> None:
20
20
  """
21
21
  # Initialize a 2D vector with the specified x and y components.
@@ -666,11 +666,25 @@ class Vector2D:
666
666
  other = self.__normalize__(other)
667
667
  return Vector2D(max(self.x, other.x), max(self.y, other.y))
668
668
 
669
+ def advanced_stringify(self:"V2|Vector2D", precision:float|None=None, use_scientific_notation:bool=False, return_as_list=False) -> str:
670
+ precision = self.round_values_on_print if precision == None else precision
671
+ def optimize(value) -> str:
672
+ abs_value = abs(value)
673
+ if abs_value < 1/10**precision and abs_value != 0:
674
+ return f"{value:.{precision}e}"
675
+ elif abs_value < 10**precision:
676
+ return f"{value:.{precision}f}".rstrip('0').rstrip('.')
677
+ else:
678
+ return f"{value:.{precision}e}"
679
+ if return_as_list:
680
+ return [optimize(self.x), optimize(self.y)] if use_scientific_notation else [f"{self.x:.{precision}f}" f"{self.y:.{precision}f}"]
681
+ return f"{optimize(self.x)}, {optimize(self.y)}" if use_scientific_notation else f"{self.x:.{precision}f}, {self.y:.{precision}f}"
682
+
669
683
  def __str__(self:"V2|Vector2D") -> str:
670
- return f"{self.x:{self.round_values_on_print}f}, {self.y:{self.round_values_on_print}f}"
684
+ return f"{self.x:.{self.round_values_on_print}f}, {self.y:.{self.round_values_on_print}f}"
671
685
 
672
686
  def __repr__(self:"V2|Vector2D") -> str:
673
- return f"x:{self.x:{self.round_values_on_print}f}\ty:{self.y:{self.round_values_on_print}f}"
687
+ return f"x:{self.x:.{self.round_values_on_print}f}\ty:{self.y:.{self.round_values_on_print}f}"
674
688
 
675
689
  def __call__(self:"V2|Vector2D", return_tuple=False) -> list|tuple:
676
690
  return (self.x, self.y) if return_tuple else [self.x, self.y]
@@ -1250,3 +1264,12 @@ def distance_line_point(line_point_a:Vector2D|V2, line_point_b:Vector2D|V2, poin
1250
1264
  The result is returned as a float representing the distance between the line segment and the point.
1251
1265
  """
1252
1266
  return float(_np.linalg.norm(_np.cross((line_point_b-line_point_a)(), (line_point_a-point_c)()))/_np.linalg.norm((line_point_b-line_point_a)()))
1267
+
1268
+ def optimize_value_string(value:int|float, precision:int) -> str:
1269
+ abs_value = abs(value)
1270
+ if abs_value < 1/10**precision and abs_value != 0:
1271
+ return f"{value:.{precision}e}"
1272
+ elif abs_value < 10**precision:
1273
+ return f"{value:.{precision}f}".rstrip('0').rstrip('.')
1274
+ else:
1275
+ return f"{value:.{precision}e}"
e2D/envs.py CHANGED
@@ -22,9 +22,9 @@ while not rootEnv.quit:
22
22
 
23
23
  pg.init()
24
24
  pg.font.init()
25
- font_arial_16 = pg.font.SysFont("Arial", 16)
26
- font_arial_32 = pg.font.SysFont("Arial", 32)
27
- font_arial_64 = pg.font.SysFont("Arial", 64)
25
+ FONT_ARIAL_16 = pg.font.SysFont("Arial", 16)
26
+ FONT_ARIAL_32 = pg.font.SysFont("Arial", 32)
27
+ FONT_ARIAL_64 = pg.font.SysFont("Arial", 64)
28
28
  create_arial_font_size = lambda size: pg.font.SysFont("Arial", size)
29
29
 
30
30
  TEXT_FIXED_SIDES_TOP_LEFT = 0
@@ -44,6 +44,8 @@ class RootEnv:
44
44
  self.screen_size :V2|Vector2D= screen_size
45
45
  self.screen = pg.display.set_mode(self.screen_size(), vsync=vsync, flags=window_flag)
46
46
  self.target_fps = target_fps
47
+ self.current_fps = self.target_fps
48
+ self.current_frame = 0
47
49
  self.show_fps = show_fps
48
50
  self.clock = pg.time.Clock()
49
51
  self.keyboard = Keyboard(self)
@@ -62,7 +64,7 @@ class RootEnv:
62
64
  def clear_rect(self, position:V2|Vector2D, size:V2|Vector2D) -> None:
63
65
  self.screen.fill(self.background_color, position() + size())
64
66
 
65
- def print(self, text:str, position:V2|Vector2D, color:tuple[float,float,float]=(255,255,255), fixed_sides=TEXT_FIXED_SIDES_TOP_LEFT, font:pg.font.Font=font_arial_32, bg_color:None|tuple[int,int,int]|list[int]=None, border_color:None|tuple[int,int,int]|list[int]=None, border_width:float=0, border_radius:int|list[int]|tuple[int,int,int,int]=-1, margin:V2|Vector2D=V2z, personalized_surface:pg.Surface|None=None) -> None:
67
+ def print(self, text:str, position:V2|Vector2D, color:tuple[float,float,float]=(255,255,255), fixed_sides=TEXT_FIXED_SIDES_TOP_LEFT, font:pg.font.Font=FONT_ARIAL_32, bg_color:None|tuple[int,int,int]|list[int]=None, border_color:None|tuple[int,int,int]|list[int]=None, border_width:float=0, border_radius:int|list[int]|tuple[int,int,int,int]=-1, margin:V2|Vector2D=V2z, personalized_surface:pg.Surface|None=None) -> None:
66
68
  text_box = font.render(text, True, color)
67
69
  size = V2(*text_box.get_size()) + margin * 2
68
70
  position = position - size * self.__fixed_sides_multiplier[fixed_sides] + margin
@@ -76,8 +78,9 @@ class RootEnv:
76
78
 
77
79
  def __draw__(self) -> None:
78
80
  self.clock.tick(self.target_fps)
81
+ self.current_fps = self.clock.get_fps()
79
82
  if self.clear_screen_each_frame: self.clear()
80
- if self.show_fps: self.print(str(round(self.clock.get_fps(),2)), self.screen_size * .01, bg_color=(0,0,0))
83
+ if self.show_fps: self.print(str(round(self.current_fps,2)), self.screen_size * .01, bg_color=(0,0,0))
81
84
 
82
85
  self.env.draw()
83
86
  pg.display.update()
@@ -91,6 +94,7 @@ class RootEnv:
91
94
  self.__update__()
92
95
  self.__draw__()
93
96
 
97
+ self.current_frame += 1
94
98
  self.events = pg.event.get()
95
99
  for event in self.events:
96
100
  if event.type == pg.QUIT or ((event.type == pg.KEYDOWN and event.key == self._quit_on_key_pressed) if self._quit_on_key_pressed != None else False):
e2D/plots.py CHANGED
@@ -2,35 +2,38 @@ from __future__ import annotations
2
2
  from .envs import *
3
3
  import numpy as np
4
4
 
5
- def no_error_complex_function(function, args) -> V2|Vector2D:
6
- res :complex= function(args)
7
- return V2(res.real, res.imag)
8
-
9
- sign = lambda value: -1 if value < 0 else (1 if value > 0 else 0)
10
-
11
5
  class Function:
12
- def __init__(self, function, color:list[float]|tuple[float,float,float]=(255,255,255)) -> None:
6
+ def __init__(self) -> None:
13
7
  self.plot : Plot
14
- self.color = color
15
- self.function = function
16
8
  self.__layer_surface__ :pg.Surface= None #type: ignore
17
9
 
18
- def update_points(self) -> None:
19
- self.update_function(self.function)
10
+ def update(self) -> None: pass
11
+
12
+ def render(self) -> None: pass
13
+
14
+ def draw(self) -> None:
15
+ self.plot.canvas.blit(self.__layer_surface__, (0,0))
16
+
17
+ class MathFunction(Function):
18
+ def __init__(self, function, color:list[float]|tuple[float,float,float]=(255,255,255)) -> None:
19
+ super().__init__()
20
+ self.color = color
21
+ self.function = function
20
22
 
21
23
  def get_points(self) -> list:
22
24
  signs_self = np.sign(self.function(*self.plot.meshgrid))
23
25
  signs_sum = signs_self + np.roll(signs_self, axis=1, shift=1) + np.roll(signs_self, axis=0, shift=-1) + np.roll(signs_self, axis=(1,0), shift=(1,-1))
24
26
  return np.column_stack(np.where(((-4 < signs_sum) & (signs_sum < 4))[:-1, 1:])[::-1]) / self.plot.scale()
25
27
 
26
- def update_function(self, new_function) -> None:
27
- self.function = new_function
28
+ def update(self, new_function=None) -> None:
29
+ if new_function != None:
30
+ self.function = new_function
28
31
  self.points = self.get_points()
29
32
  self.render()
30
33
 
31
- def get_derivative(self, delta:float=.01, color:None|list[float]|tuple[float,float,float]=None) -> Function:
32
- return Function(lambda x,y: (self.function(x + delta, y) - self.function(x,y))/delta - y, color if color != None else self.color)
33
-
34
+ def get_derivative(self, delta:float=.01, color:None|list[float]|tuple[float,float,float]=None) -> MathFunction:
35
+ return MathFunction(lambda x,y: (self.function(x + delta, y) - self.function(x,y))/delta - y, color if color != None else self.color)
36
+
34
37
  def render(self) -> None:
35
38
  self.__layer_surface__.fill((0,0,0,0))
36
39
  offset = self.plot.dragging - self.plot.start_dragging if (self.plot.dragging != None) and (not self.plot.settings.get("use_real_time_rendering")) else V2z
@@ -44,44 +47,70 @@ class Function:
44
47
  point = point.astype(int).tolist()
45
48
  if self.plot.dragging != None:
46
49
  point = round(point + offset)()
47
- self.__layer_surface__.set_at(point, self.color)
50
+ self.__layer_surface__.set_at(point, self.color) #type: ignore
48
51
 
49
- def draw(self) -> None:
50
- self.plot.canvas.blit(self.__layer_surface__, (0,0))
52
+ class PointsFunction(Function):
53
+ def __init__(self, points:list[V2|Vector2D]=[], points_color:list[float]|tuple[float,float,float]=(255,0,0), color:list[float]|tuple[float,float,float]=(255,255,255)) -> None:
54
+ super().__init__()
55
+ self.color = color
56
+ self.points = points
57
+ self.points_color = points_color
58
+
59
+ def update(self, points:list[V2|Vector2D]|None=None) -> None:
60
+ if points != None: self.points = points
61
+ self.plot_points = [self.plot.__plot2real__(point)() for point in self.points if \
62
+ self.plot.top_left_x < point.x < self.plot.bottom_right_x and \
63
+ self.plot.bottom_right_y < point.y < self.plot.top_left_y]
64
+ self.render()
51
65
 
52
- # class ComplexFunction:
53
- # def __init__(self, function, plot:"Plot", starting_t:float=-10, ending_t:float=10, step=.01, color=(255,255,255), auto_connect_treshold=float("inf"), points_radius=2, points_color=None) -> None:
54
- # self.auto_connect_treshold = auto_connect_treshold
55
- # self.plot = plot
56
- # self.starting_t = starting_t
57
- # self.ending_t = ending_t
58
- # self.color = color
59
- # self.step = step
60
- # self.points_color = points_color
61
- # self.points_radius = points_radius
62
- # self.update_function(function)
66
+ def render(self) -> None:
67
+ self.__layer_surface__.fill((0,0,0,0))
68
+ if len(self.plot_points)>=2: pg.draw.lines(self.__layer_surface__, self.color, False, self.plot_points)
69
+ # for point in self.points:
70
+ # pg.draw.circle(self.__layer_surface__,
71
+ # self.points_color,
72
+ # self.plot.__plot2real__(point),
73
+ # 5)
74
+
75
+ """
76
+ def no_error_complex_function(function, args) -> V2|Vector2D:
77
+ res :complex= function(args)
78
+ return V2(res.real, res.imag)
79
+ sign = lambda value: -1 if value < 0 else (1 if value > 0 else 0)
80
+ class ComplexFunction:
81
+ def __init__(self, function, plot:"Plot", starting_t:float=-10, ending_t:float=10, step=.01, color=(255,255,255), auto_connect_treshold=float("inf"), points_radius=2, points_color=None) -> None:
82
+ self.auto_connect_treshold = auto_connect_treshold
83
+ self.plot = plot
84
+ self.starting_t = starting_t
85
+ self.ending_t = ending_t
86
+ self.color = color
87
+ self.step = step
88
+ self.points_color = points_color
89
+ self.points_radius = points_radius
90
+ self.update_function(function)
63
91
 
64
- # def update_points(self) -> None:
65
- # self.update_function(self.function)
92
+ def update_points(self) -> None:
93
+ self.update_function(self.function)
66
94
 
67
- # def update_function(self, new_function) -> None:
68
- # self.function = new_function
69
- # self.points :list[V2|Vector2D]= [point for t in range(int(self.starting_t / self.step), int(self.ending_t / self.step)) if (self.plot.bottom_right_y < (point:=no_error_complex_function(new_function, t * self.step)).y < self.plot.top_left_y) and (self.plot.top_left_x < point.x < self.plot.bottom_right_x)]
70
- # self.full_auto_connect = not any(point.distance_to(self.points[i]) > self.auto_connect_treshold for i,point in enumerate(self.points[1:]))
71
-
72
- # def draw(self) -> None:
73
- # if self.points_radius:
74
- # for point in self.points:
75
- # pg.draw.circle(self.plot.canvas, self.color if self.points_color == None else self.points_color, self.plot.__plot2real__(point)(), self.points_radius)
76
-
77
- # if len(self.points) < 2: return
78
- # if self.full_auto_connect:
79
- # pg.draw.lines(self.plot.canvas, self.color, False, [self.plot.__plot2real__(point)() for point in self.points])
80
- # else:
81
- # real_points = [self.plot.__plot2real__(point)() for point in self.points]
82
- # for i,(point, real_point) in enumerate(zip(self.points[1:], real_points[1:])):
83
- # if point.distance_to(self.points[i]) < self.auto_connect_treshold:
84
- # pg.draw.line(self.plot.canvas, self.color, real_points[i], real_point) #type: ignore
95
+ def update_function(self, new_function) -> None:
96
+ self.function = new_function
97
+ self.points :list[V2|Vector2D]= [point for t in range(int(self.starting_t / self.step), int(self.ending_t / self.step)) if (self.plot.bottom_right_y < (point:=no_error_complex_function(new_function, t * self.step)).y < self.plot.top_left_y) and (self.plot.top_left_x < point.x < self.plot.bottom_right_x)]
98
+ self.full_auto_connect = not any(point.distance_to(self.points[i]) > self.auto_connect_treshold for i,point in enumerate(self.points[1:]))
99
+
100
+ def draw(self) -> None:
101
+ if self.points_radius:
102
+ for point in self.points:
103
+ pg.draw.circle(self.plot.canvas, self.color if self.points_color == None else self.points_color, self.plot.__plot2real__(point)(), self.points_radius)
104
+
105
+ if len(self.points) < 2: return
106
+ if self.full_auto_connect:
107
+ pg.draw.lines(self.plot.canvas, self.color, False, [self.plot.__plot2real__(point)() for point in self.points])
108
+ else:
109
+ real_points = [self.plot.__plot2real__(point)() for point in self.points]
110
+ for i,(point, real_point) in enumerate(zip(self.points[1:], real_points[1:])):
111
+ if point.distance_to(self.points[i]) < self.auto_connect_treshold:
112
+ pg.draw.line(self.plot.canvas, self.color, real_points[i], real_point) #type: ignore
113
+ """
85
114
 
86
115
  class __PlotSettings__:
87
116
  def __init__(self, plot:Plot) -> None:
@@ -91,7 +120,6 @@ class __PlotSettings__:
91
120
  "distance_to_axis_for_scalar_zoom" : 10,
92
121
 
93
122
  # cursor
94
- "show_cursor_coords" : False,
95
123
  "zoom_on_center" : False,
96
124
 
97
125
  # plot visual options
@@ -123,6 +151,9 @@ class __PlotSettings__:
123
151
  "show_pointer" : True,
124
152
  "pointer_radius" : 15,
125
153
  "pointer_color" : rgb(255, 255, 255),
154
+
155
+ # cursor
156
+ "show_cursor_coords" : False,
126
157
 
127
158
  #rect
128
159
  "render_bg" : True,
@@ -134,8 +165,9 @@ class __PlotSettings__:
134
165
 
135
166
  # info options
136
167
  "show_zoom_info": True,
137
- "top_left_info_position" : self.plot.position + V2(20, 100),
138
- "info_interline_space" : V2(0, 32),
168
+ "top_left_info_position" : self.plot.position + V2(15, 75),
169
+ "info_interline_space" : V2(0, 24),
170
+ "info_font" : create_arial_font_size(24),
139
171
  "info_precision" : 2,
140
172
  }
141
173
 
@@ -182,11 +214,6 @@ class Plot:
182
214
  self.scale = scale
183
215
 
184
216
  self.settings = __PlotSettings__(self)
185
-
186
- self.current_zoom = V2one * -np.log2(10)*10
187
- self.current_offset = V2(0,0)
188
- self.update_grid(True)
189
-
190
217
  self.functions :list[Function]= []
191
218
 
192
219
  self.canvas = pg.Surface(self.size(), pg.SRCALPHA, 32).convert_alpha()
@@ -195,6 +222,8 @@ class Plot:
195
222
  self.is_mouse_in_rect = False
196
223
  self.mouse_scalar = V2one.copy()
197
224
 
225
+ self.focus(V2(0,0), 10)
226
+
198
227
  def set_borders_by_position_and_zoom(self) -> None:
199
228
  self.top_left_plot_coord = self.current_offset - (.5**(.1*self.current_zoom)) * self.__y_axis_multiplier__
200
229
  self.bottom_right_plot_coord = self.current_offset + (.5**(.1*self.current_zoom)) * self.__y_axis_multiplier__
@@ -214,7 +243,7 @@ class Plot:
214
243
  def load_function(self, function:Function) -> None:
215
244
  function.plot = self
216
245
  function.__layer_surface__ = pg.Surface(self.size(), pg.SRCALPHA, 32).convert_alpha()
217
- function.update_function(function.function)
246
+ function.update()
218
247
  self.functions.append(function)
219
248
 
220
249
  def __plot2real__(self, plot_position:V2|Vector2D) -> V2|Vector2D:
@@ -234,31 +263,31 @@ class Plot:
234
263
  grid_width = self.settings.get("grid_width")
235
264
  clamped_top_left = grid_step * (self.top_left_plot_coord / grid_step).__ceil__()
236
265
  clamped_bottom_right = grid_step * (self.bottom_right_plot_coord / grid_step).__ceil__()
237
- for x_value in np.arange(clamped_top_left.x, clamped_bottom_right.x, grid_step.x):
238
- pg.draw.line( self.canvas, grid_color, self.__plot2real__((x_value, self.top_left_y))(), self.__plot2real__((x_value, self.bottom_right_y))(), grid_width)
239
- for y_value in np.arange(clamped_bottom_right.y, clamped_top_left.y, grid_step.y):
240
- pg.draw.line(self.canvas, grid_color, self.__plot2real__((self.top_left_x, y_value))(), self.__plot2real__((self.bottom_right_x, y_value))(), grid_width)
266
+ for x_value in np.arange(clamped_top_left.x, clamped_bottom_right.x, grid_step.x): #type: ignore
267
+ pg.draw.line( self.canvas, grid_color, self.__plot2real__((x_value, self.top_left_y))(), self.__plot2real__((x_value, self.bottom_right_y))(), grid_width) #type: ignore
268
+ for y_value in np.arange(clamped_bottom_right.y, clamped_top_left.y, grid_step.y): #type: ignore
269
+ pg.draw.line(self.canvas, grid_color, self.__plot2real__((self.top_left_x, y_value))(), self.__plot2real__((self.bottom_right_x, y_value))(), grid_width) #type: ignore
241
270
 
242
271
  # draw functions
243
272
  for function in self.functions: function.draw()
244
273
 
245
274
  # draw rect, pointer and corner coords
246
275
  if self.settings.get("draw_rect"):
247
- pg.draw.rect(self.canvas, self.settings.get("rect_color"), V2z() + self.size(), self.settings.get("rect_width"))
276
+ pg.draw.rect(self.canvas, self.settings.get("rect_color"), V2z() + self.size(), self.settings.get("rect_width")) #type: ignore
248
277
 
249
278
  if self.settings.get("show_pointer"):
250
279
  center = self.size * .5
251
280
  aimer_radius = self.settings.get("pointer_radius")
252
281
  pointer_color = self.settings.get("pointer_color")
253
- pg.draw.line(self.canvas, pointer_color, (center + aimer_radius)(), (center - aimer_radius)(), 1)
254
- pg.draw.line(self.canvas, pointer_color, (center + self.__y_axis_multiplier__ * aimer_radius)(), (center - self.__y_axis_multiplier__ * aimer_radius)(), 1)
255
- pg.draw.circle(self.canvas, pointer_color, (self.size * .5)(), 15, 1)
282
+ pg.draw.line(self.canvas, pointer_color, (center + aimer_radius)(), (center - aimer_radius)(), 1) #type: ignore
283
+ pg.draw.line(self.canvas, pointer_color, (center + self.__y_axis_multiplier__ * aimer_radius)(), (center - self.__y_axis_multiplier__ * aimer_radius)(), 1) #type: ignore
284
+ pg.draw.circle(self.canvas, pointer_color, (self.size * .5)(), 15, 1) #type: ignore
256
285
 
257
286
  if self.settings.get("show_corners_coords"):
258
- self.rootEnv.print(str(self.top_left_plot_coord), V2z.copy(), bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
259
- self.rootEnv.print(str(V2(self.top_left_plot_coord.x, self.bottom_right_plot_coord.y)), self.size * V2(0, 1), fixed_sides=TEXT_FIXED_SIDES_BOTTOM_LEFT, bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
260
- self.rootEnv.print(str(self.bottom_right_plot_coord), self.size.copy(), fixed_sides=TEXT_FIXED_SIDES_BOTTOM_RIGHT, bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
261
- self.rootEnv.print(str(V2(self.bottom_right_plot_coord.x, self.top_left_plot_coord.y)), self.size * V2(1, 0), fixed_sides=TEXT_FIXED_SIDES_TOP_RIGHT, bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
287
+ self.rootEnv.print(self.top_left_plot_coord.advanced_stringify(4, True), V2z.copy(), bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
288
+ self.rootEnv.print(V2(self.top_left_plot_coord.x, self.bottom_right_plot_coord.y).advanced_stringify(4, True), self.size * V2(0, 1), fixed_sides=TEXT_FIXED_SIDES_BOTTOM_LEFT, bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
289
+ self.rootEnv.print(self.bottom_right_plot_coord.advanced_stringify(4, True), self.size.copy(), fixed_sides=TEXT_FIXED_SIDES_BOTTOM_RIGHT, bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
290
+ self.rootEnv.print(V2(self.bottom_right_plot_coord.x, self.top_left_plot_coord.y).advanced_stringify(4, True), self.size * V2(1, 0), fixed_sides=TEXT_FIXED_SIDES_TOP_RIGHT, bg_color=(0,0,0), border_color=(255,255,255), border_width=2, border_radius=15, margin=V2(10,10), personalized_surface=self.canvas)
262
291
 
263
292
  def update(self) -> None:
264
293
  # update mouse and center positions
@@ -271,10 +300,7 @@ class Plot:
271
300
  # render the functions when i stop dragging (when i release the left mouse key)
272
301
  if self.rootEnv.mouse.just_released[0] and self.dragging != None:
273
302
  self.dragging = None
274
- self.update_grid(True)
275
- for function in self.functions:
276
- function.update_points()
277
- self.render()
303
+ self.focus(None, None)
278
304
 
279
305
  if self.is_mouse_in_rect:
280
306
  # mouse scalar is needed for checking if the mouse is hovering an axis, in case it is the opposite one zoom value has to be multiplied by 0 so nullifying it.
@@ -292,10 +318,7 @@ class Plot:
292
318
  # i have to update the corners of the plot here to use the real2plot function correctly (i cant use shortcuts)
293
319
  self.update_grid(False)
294
320
  self.current_offset += pre - self.__real2plot__(self.rootEnv.mouse.position)
295
- self.update_grid(True)
296
- for function in self.functions:
297
- function.update_points()
298
- self.render()
321
+ self.focus(None, None)
299
322
 
300
323
  # start dragging whenever mouse left button is just pressed
301
324
  if self.rootEnv.mouse.just_pressed[0] and self.dragging == None:
@@ -304,22 +327,49 @@ class Plot:
304
327
 
305
328
  # update the canvas if im dragging
306
329
  if self.dragging:
307
- offset = (self.dragging - self.rootEnv.mouse.position)* V2(1, -1) * (abs(self.bottom_right_plot_coord - self.top_left_plot_coord) / self.size)
330
+ moved = False
331
+ if not self.is_mouse_in_rect:
332
+ if self.rootEnv.mouse.position.x < self.position.x:
333
+ self.rootEnv.mouse.set_position(V2(self.position.x + self.size.x, self.rootEnv.mouse.position.y))
334
+ moved = True
335
+ elif self.rootEnv.mouse.position.x > self.position.x + self.size.x:
336
+ self.rootEnv.mouse.set_position(V2(self.position.x, self.rootEnv.mouse.position.y))
337
+ moved = True
338
+ if self.rootEnv.mouse.position.y < self.position.y:
339
+ self.rootEnv.mouse.set_position(V2(self.rootEnv.mouse.position.x, self.position.y + self.size.y))
340
+ moved = True
341
+ elif self.rootEnv.mouse.position.y > self.position.y + self.size.y:
342
+ self.rootEnv.mouse.set_position(V2(self.rootEnv.mouse.position.x, self.position.y))
343
+ moved = True
344
+ if not moved:
345
+ offset = (self.dragging - self.rootEnv.mouse.position)* V2(1, -1) * (abs(self.bottom_right_plot_coord - self.top_left_plot_coord) / self.size)
346
+ self.current_offset += offset
308
347
  self.dragging = self.rootEnv.mouse.position.copy()
309
- self.current_offset += offset
310
348
 
311
349
  # with real time rendering i update the function render each frame whnever im dragging the canvs around
312
350
  if self.settings.get("use_real_time_rendering"):
313
- self.update_grid(True)
314
- for function in self.functions: function.update_points()
351
+ self.focus(None, None)
315
352
  else:
316
353
  self.update_grid()
317
- self.render()
354
+ self.render()
355
+
356
+ def focus(self, center:V2|Vector2D|None=V2z, zoom:float|Vector2D|V2|None=10.0) -> None:
357
+ if center != None:
358
+ self.current_offset = center.copy()
359
+ if zoom != None:
360
+ if any(isinstance(zoom, cls) for cls in {Vector2D, V2}):
361
+ self.current_zoom = 0-V2(np.log2(zoom.x), np.log2(zoom.y)) * 10
362
+ else:
363
+ self.current_zoom = V2one * -np.log2(zoom)*10
364
+
365
+ self.update_grid(True)
366
+ for function in self.functions: function.update()
367
+ self.render()
318
368
 
319
369
  def draw(self) -> None:
320
370
  # fill canvas with bg color
321
371
  if self.settings.get("render_bg"):
322
- self.rootEnv.screen.fill(self.settings.get("bg_color"), self.position() + self.size())
372
+ self.rootEnv.screen.fill(self.settings.get("bg_color"), self.position() + self.size()) #type: ignore
323
373
 
324
374
  # render functions before axes
325
375
  if render_axes_on_top:=self.settings.get("render_axes_on_top"): self.rootEnv.screen.blit(self.canvas, self.position())
@@ -327,13 +377,13 @@ class Plot:
327
377
  # render axes
328
378
  if self.top_left_x < 0 < self.bottom_right_x and (self.settings.get("show_x_axis") and self.settings.get("show_axes")):
329
379
  pg.draw.line(self.rootEnv.screen,
330
- (self.settings.get("axes_default_color") if (x_color:=self.settings.get("x_axis_color"))==None else x_color) if self.mouse_scalar.x else (self.settings.get("mouse_hover_axes_color")),
380
+ (self.settings.get("axes_default_color") if (x_color:=self.settings.get("x_axis_color"))==None else x_color) if self.mouse_scalar.x else (self.settings.get("mouse_hover_axes_color")), #type: ignore
331
381
  (self.__plot2real__(V2(0, self.top_left_y)) + self.position)(),
332
382
  (self.__plot2real__(V2(0, self.bottom_right_y)) + self.position)(),
333
383
  self.settings.get("axes_default_width") if (x_width:=self.settings.get("x_axis_width"))==None else x_width) #type: ignore
334
384
  if self.bottom_right_y < 0 < self.top_left_y and (self.settings.get("show_y_axis") and self.settings.get("show_axes")):
335
385
  pg.draw.line(self.rootEnv.screen,
336
- (self.settings.get("axes_default_color") if (y_color:=self.settings.get("y_axis_color"))==None else y_color) if self.mouse_scalar.y else (self.settings.get("mouse_hover_axes_color")),
386
+ (self.settings.get("axes_default_color") if (y_color:=self.settings.get("y_axis_color"))==None else y_color) if self.mouse_scalar.y else (self.settings.get("mouse_hover_axes_color")), #type: ignore
337
387
  (self.__plot2real__(V2(self.top_left_x, 0)) + self.position)(),
338
388
  (self.__plot2real__(V2(self.bottom_right_x, 0)) + self.position)(),
339
389
  self.settings.get("axes_default_width") if (y_width:=self.settings.get("y_axis_width"))==None else y_width) #type: ignore
@@ -342,14 +392,17 @@ class Plot:
342
392
  if not render_axes_on_top: self.rootEnv.screen.blit(self.canvas, self.position())
343
393
 
344
394
  if self.is_mouse_in_rect and self.settings.get("show_cursor_coords"):
345
- self.rootEnv.print(str(self.plot_mouse_position), self.rootEnv.mouse.position, fixed_sides=TEXT_FIXED_SIDES_BOTTOM_MIDDLE) #type: ignore
395
+ self.rootEnv.print(self.plot_mouse_position.advanced_stringify(3, True), self.rootEnv.mouse.position, fixed_sides=TEXT_FIXED_SIDES_BOTTOM_MIDDLE) #type: ignore
396
+
346
397
 
398
+ current_real_zoom = (.5**(.1*self.current_zoom)).advanced_stringify(self.settings.get('info_precision'), True, True)
347
399
  data = [
348
400
  [f"ZOOM:", TEXT_FIXED_SIDES_TOP_LEFT, self.settings.get("show_zoom_info")],
349
- [f" x: {(.5**(.1*self.current_zoom.x)):.{self.settings.get('info_precision')}f};", TEXT_FIXED_SIDES_TOP_LEFT, self.settings.get("show_zoom_info")],
350
- [f" y: {(.5**(.1*self.current_zoom.y)):.{self.settings.get('info_precision')}f};", TEXT_FIXED_SIDES_TOP_LEFT, self.settings.get("show_zoom_info")],
401
+ [f" x: {current_real_zoom[0]};", TEXT_FIXED_SIDES_TOP_LEFT, self.settings.get("show_zoom_info")],
402
+ [f" y: {current_real_zoom[1]};", TEXT_FIXED_SIDES_TOP_LEFT, self.settings.get("show_zoom_info")],
403
+ [f" ratio: {optimize_value_string(self.current_zoom.x / self.current_zoom.y, 4)};", TEXT_FIXED_SIDES_TOP_LEFT, self.settings.get("show_zoom_info")],
351
404
  ]
352
405
 
353
406
  for i, (d, fixed_side, show) in enumerate(data):
354
407
  if show:
355
- self.rootEnv.print(d, self.settings.get("top_left_info_position") + self.settings.get("info_interline_space") * i, fixed_sides=fixed_side) #type: ignore
408
+ self.rootEnv.print(d, self.settings.get("top_left_info_position") + self.settings.get("info_interline_space") * i, fixed_sides=fixed_side, font=self.settings.get("info_font"))
e2D/utils.py CHANGED
@@ -18,6 +18,10 @@ class Mouse:
18
18
  self.last_frame_movement = V2z.copy()
19
19
  self.update()
20
20
 
21
+ def set_position(self, new_position:Vector2D|V2) -> None:
22
+ self.position = new_position
23
+ pg.mouse.set_pos(new_position())
24
+
21
25
  def update(self) -> None:
22
26
  self.position = V2(*pg.mouse.get_pos()) # type: ignore
23
27
  self.last_frame_movement = V2(*pg.mouse.get_rel())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: e2D
3
- Version: 1.3.9
3
+ Version: 1.3.11
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
@@ -0,0 +1,9 @@
1
+ e2D/__init__.py,sha256=5cJrfMFX1jhMADrf2PH8Rr1yL-ZgZVdRg3k_HLym2zs,57567
2
+ e2D/envs.py,sha256=ULXoK0yDM9_Z2iCQpMXEYo1Fr4NhKoDXFQXyG3CtOdU,4083
3
+ e2D/plots.py,sha256=xlkFJNDTeJEDVloMgyISOfS_oWHpJ7q9_3HkKGwydjA,23402
4
+ e2D/utils.py,sha256=hGO9WhvDvE6wDDw0vIEjVCis64aTOMgrssx-P0_znhI,5513
5
+ e2D-1.3.11.dist-info/LICENSE,sha256=wymkNVDvj3qmjdO_rAhkRPM4t5y3_SqffGsFdgfvznU,1066
6
+ e2D-1.3.11.dist-info/METADATA,sha256=sYCWrReK8vO260de8rdNeo0s9VhGDu8PJWgJGT__I3o,9609
7
+ e2D-1.3.11.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
8
+ e2D-1.3.11.dist-info/top_level.txt,sha256=3vKZ-CGzNlTCpzVMmM0Ht76krCofKw7hZ0wBf-dnKdM,4
9
+ e2D-1.3.11.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- e2D/__init__.py,sha256=L4wmmedzo_SQUIcCwPYTMJTuqYi_lASRdCwL1q0Q2rw,56327
2
- e2D/envs.py,sha256=myRralRCZeuadguczadi7lXUPOZdNwlnTw0M3oNpNFE,3933
3
- e2D/plots.py,sha256=WCANUHZQE0vmUR4rg9gQVShbljxZ-Dz6ae3VhNO6PSo,20418
4
- e2D/utils.py,sha256=sq9efoNnSlJAfjvf18qDQpvO1jyz-9-mWBW3P4WMkD4,5368
5
- e2D-1.3.9.dist-info/LICENSE,sha256=wymkNVDvj3qmjdO_rAhkRPM4t5y3_SqffGsFdgfvznU,1066
6
- e2D-1.3.9.dist-info/METADATA,sha256=ZVXNZs-NxLBNIDlB8rBIc3HQEfeCUeC7Yu5e1yLWYb0,9608
7
- e2D-1.3.9.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
8
- e2D-1.3.9.dist-info/top_level.txt,sha256=3vKZ-CGzNlTCpzVMmM0Ht76krCofKw7hZ0wBf-dnKdM,4
9
- e2D-1.3.9.dist-info/RECORD,,
File without changes
File without changes