e2D 2.0.0__cp313-cp313-win_amd64.whl → 2.0.1__cp313-cp313-win_amd64.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/plots.pyi ADDED
@@ -0,0 +1,238 @@
1
+ """
2
+ Type stubs for plots module
3
+ 2D plotting with GPU-accelerated rendering
4
+ """
5
+
6
+ from typing import Optional, Callable
7
+ from enum import Enum
8
+ import numpy as np
9
+ import numpy.typing as npt
10
+ from .types import BufferType, ColorType, ComputeShaderType, ContextType, ProgramType, VAOType, VectorType
11
+ from .color_defs import GRAY10, GRAY50, WHITE, RED, CYAN, TRANSPARENT
12
+
13
+ class ShaderManager:
14
+ """Cache and manage shader files for the plots module."""
15
+ _cache: dict[str, str]
16
+
17
+ @staticmethod
18
+ def load_shader(path: str) -> str:
19
+ """Load a shader file with caching."""
20
+ ...
21
+
22
+ @staticmethod
23
+ def create_program(ctx: ContextType, vertex_path: str, fragment_path: str) -> ProgramType:
24
+ """Create a program from shader files."""
25
+ ...
26
+
27
+ @staticmethod
28
+ def create_compute(ctx: ContextType, compute_path: str) -> ComputeShaderType:
29
+ """Create a compute shader from file."""
30
+ ...
31
+
32
+ class View2D:
33
+ """
34
+ Manages coordinate space (World <-> Clip) via UBO.
35
+ """
36
+ ctx: ContextType
37
+ binding: int
38
+ center: npt.NDArray[np.float32]
39
+ zoom: float
40
+ aspect: float
41
+ resolution: npt.NDArray[np.float32]
42
+ buffer: BufferType
43
+
44
+ def __init__(self, ctx: ContextType, binding: int = 0) -> None: ...
45
+
46
+ def update_win_size(self, width: int, height: int) -> None: ...
47
+ def pan(self, dx: float, dy: float) -> None: ...
48
+ def zoom_step(self, factor: float) -> None: ...
49
+ def zoom_at(self, factor: float, ndc_x: float, ndc_y: float) -> None: ...
50
+ def update_buffer(self) -> None: ...
51
+
52
+ class PlotSettings:
53
+ bg_color: ColorType
54
+ show_axis: bool
55
+ axis_color: ColorType
56
+ axis_width: float
57
+ show_grid: bool
58
+ grid_color: ColorType
59
+ grid_spacing: float
60
+
61
+ def __init__(
62
+ self,
63
+ bg_color: ColorType = (0.1, 0.1, 0.1, 1.0),
64
+ show_axis: bool = True,
65
+ axis_color: ColorType = (0.5, 0.5, 0.5, 1.0),
66
+ axis_width: float = 2.0,
67
+ show_grid: bool = True,
68
+ grid_color: ColorType = (0.2, 0.2, 0.2, 1.0),
69
+ grid_spacing: float = 1.0
70
+ ) -> None: ...
71
+
72
+ class CurveSettings:
73
+ color: ColorType
74
+ width: float
75
+ count: int
76
+
77
+ def __init__(
78
+ self,
79
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
80
+ width: float = 2.0,
81
+ count: int = 1024
82
+ ) -> None:
83
+ self.color = color
84
+ self.width = width
85
+ self.count = count
86
+
87
+ class ImplicitSettings:
88
+ color: ColorType
89
+ thickness: float
90
+
91
+ def __init__(
92
+ self,
93
+ color: ColorType = (0.4, 0.6, 1.0, 1.0),
94
+ thickness: float = 2.0
95
+ ) -> None: ...
96
+
97
+ class LineType(Enum):
98
+ NONE: int
99
+ DIRECT: int
100
+ BEZIER_QUADRATIC: int
101
+ BEZIER_CUBIC: int
102
+ SMOOTH: int
103
+
104
+ class StreamSettings:
105
+ point_color: ColorType
106
+ point_radius: float
107
+ show_points: bool
108
+ round_points: bool
109
+ line_type: LineType
110
+ line_color: ColorType
111
+ line_width: float
112
+ curve_segments: int
113
+
114
+ def __init__(
115
+ self,
116
+ point_color: ColorType = (1.0, 0.0, 0.0, 1.0),
117
+ point_radius: float = 5.0,
118
+ show_points: bool = True,
119
+ round_points: bool = True,
120
+ line_type: LineType|int = LineType.DIRECT,
121
+ line_color: ColorType = (1.0, 0.0, 0.0, 1.0),
122
+ line_width: float = 2.0,
123
+ curve_segments: int = 10
124
+ ) -> None: ...
125
+
126
+ class Plot2D:
127
+ """A specific rectangular area on the screen for plotting."""
128
+ ctx: ContextType
129
+ top_left: VectorType
130
+ bottom_right: VectorType
131
+ settings: PlotSettings
132
+ width: int
133
+ height: int
134
+ view: View2D
135
+ viewport: tuple[int, int, int, int]
136
+ grid_prog: ProgramType
137
+ grid_quad: BufferType
138
+ grid_vao: VAOType
139
+ is_dragging: bool
140
+ last_mouse_pos: VectorType
141
+
142
+ def __init__(
143
+ self,
144
+ ctx: ContextType,
145
+ top_left: VectorType,
146
+ bottom_right: VectorType,
147
+ settings: Optional[PlotSettings] = None
148
+ ) -> None: ...
149
+
150
+ def set_rect(self, top_left: VectorType, bottom_right: VectorType) -> None: ...
151
+ def update_window_size(self, win_width: int, win_height: int) -> None: ...
152
+ def render(self, draw_callback: Callable[[], None]) -> None: ...
153
+ def contains(self, x: float, y: float) -> bool: ...
154
+ def on_mouse_drag(self, dx: float, dy: float) -> None: ...
155
+ def on_scroll(self, yoffset: float, mouse_x: float, mouse_y: float) -> None: ...
156
+
157
+ class GpuStream:
158
+ """Ring-buffer on GPU for high-performance point streaming."""
159
+ ctx: ContextType
160
+ capacity: int
161
+ settings: StreamSettings
162
+ head: int
163
+ size: int
164
+ buffer: BufferType
165
+ prog: ProgramType
166
+ vao: VAOType
167
+ smooth_prog: ProgramType
168
+ smooth_vao: VAOType
169
+
170
+ def __init__(
171
+ self,
172
+ ctx: ContextType,
173
+ capacity: int = 100000,
174
+ settings: Optional[StreamSettings] = None
175
+ ) -> None: ...
176
+
177
+ def push(self, points: npt.NDArray[np.float32]) -> None: ...
178
+ def draw(self) -> None: ...
179
+ def shift_points(self, offset: VectorType) -> None: ...
180
+
181
+ class ComputeCurve:
182
+ """Parametric curve p(t) evaluated entirely on GPU."""
183
+ ctx: ContextType
184
+ count: int
185
+ t_range: tuple[float, float]
186
+ settings: CurveSettings
187
+ vbo: BufferType
188
+ compute_prog: ComputeShaderType
189
+ render_prog: ProgramType
190
+ vao: VAOType
191
+
192
+ def __init__(
193
+ self,
194
+ ctx: ContextType,
195
+ func_body: str,
196
+ t_range: tuple[float, float],
197
+ count: int = 1024,
198
+ settings: Optional[CurveSettings] = None
199
+ ) -> None: ...
200
+
201
+ def update(self) -> None: ...
202
+ def draw(self) -> None: ...
203
+
204
+ class ImplicitPlot:
205
+ """Rendering of f(x,y)=0 via Fragment Shader and SDF."""
206
+ ctx: ContextType
207
+ settings: ImplicitSettings
208
+ quad: BufferType
209
+ prog: ProgramType
210
+ vao: VAOType
211
+
212
+ def __init__(
213
+ self,
214
+ ctx: ContextType,
215
+ func_body: str,
216
+ settings: Optional[ImplicitSettings] = None
217
+ ) -> None: ...
218
+
219
+ def draw(self) -> None: ...
220
+
221
+ class SegmentDisplay:
222
+ """Simple 7-segment display renderer for numbers."""
223
+ ctx: ContextType
224
+ prog: ProgramType
225
+ vbo: BufferType
226
+ vao: VAOType
227
+ digits: dict[str, list[int]]
228
+
229
+ def __init__(self, ctx: ContextType) -> None: ...
230
+
231
+ def draw_number(
232
+ self,
233
+ text: str,
234
+ x: float,
235
+ y: float,
236
+ size: float = 20.0,
237
+ color: ColorType = (1.0, 1.0, 1.0, 1.0)
238
+ ) -> None: ...
e2D/shapes.py CHANGED
@@ -1,6 +1,9 @@
1
1
  import moderngl
2
2
  import numpy as np
3
3
  from .commons import get_pattr, get_pattr_value, set_pattr_value
4
+ from .types import VAOType, VectorType, ColorType, ContextType, ProgramType, BufferType
5
+ from .colors import normalize_color
6
+ from .color_defs import WHITE, BLACK, TRANSPARENT
4
7
  from typing import Optional, Sequence
5
8
  from enum import Enum
6
9
 
@@ -12,8 +15,15 @@ class FillMode(Enum):
12
15
 
13
16
  class ShapeLabel:
14
17
  """A pre-rendered shape for efficient repeated drawing."""
15
- def __init__(self, ctx: moderngl.Context, prog: moderngl.Program,
16
- vbo: moderngl.Buffer, vertex_count: int, shape_type: str = 'line') -> None:
18
+ ctx: ContextType
19
+ prog: ProgramType
20
+ vbo: BufferType
21
+ vao: VAOType
22
+ vertex_count: int
23
+ shape_type: str
24
+
25
+ def __init__(self, ctx: ContextType, prog: ProgramType,
26
+ vbo: BufferType, vertex_count: int, shape_type: str = 'line') -> None:
17
27
  self.ctx = ctx
18
28
  self.prog = prog
19
29
  self.vbo = vbo
@@ -45,7 +55,18 @@ class ShapeLabel:
45
55
 
46
56
  class InstancedShapeBatch:
47
57
  """High-performance instanced batch for drawing thousands of shapes with minimal CPU overhead."""
48
- def __init__(self, ctx: moderngl.Context, prog: moderngl.Program, shape_type: str = 'circle', max_instances: int = 100000) -> None:
58
+ ctx: ContextType
59
+ prog: ProgramType
60
+ shape_type: str
61
+ max_instances: int
62
+ instance_count: int
63
+ floats_per_instance: int
64
+ instance_buffer: BufferType
65
+ quad_vbo: BufferType
66
+ vao: VAOType
67
+ instance_data: list[float]
68
+
69
+ def __init__(self, ctx: ContextType, prog: ProgramType, shape_type: str = 'circle', max_instances: int = 100000) -> None:
49
70
  self.ctx = ctx
50
71
  self.prog = prog
51
72
  self.shape_type = shape_type
@@ -128,9 +149,9 @@ class InstancedShapeBatch:
128
149
 
129
150
  self.instance_data = []
130
151
 
131
- def add_circle(self, center: tuple[float, float], radius: float,
132
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
133
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
152
+ def add_circle(self, center: VectorType, radius: float,
153
+ color: ColorType = WHITE,
154
+ border_color: ColorType = TRANSPARENT,
134
155
  border_width: float = 0.0,
135
156
  antialiasing: float = 1.0) -> None:
136
157
  """Add a circle instance to the batch."""
@@ -171,10 +192,10 @@ class InstancedShapeBatch:
171
192
  self.instance_data.extend(data.ravel())
172
193
  self.instance_count += n
173
194
 
174
- def add_rect(self, center: tuple[float, float], size: tuple[float, float],
175
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
195
+ def add_rect(self, center: VectorType, size: VectorType,
196
+ color: ColorType = WHITE,
176
197
  corner_radius: float = 0.0,
177
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
198
+ border_color: ColorType = TRANSPARENT,
178
199
  border_width: float = 0.0,
179
200
  antialiasing: float = 1.0,
180
201
  rotation: float = 0.0) -> None:
@@ -225,9 +246,9 @@ class InstancedShapeBatch:
225
246
  self.instance_data.extend(data.ravel())
226
247
  self.instance_count += n
227
248
 
228
- def add_line(self, start: tuple[float, float], end: tuple[float, float],
249
+ def add_line(self, start: VectorType, end: VectorType,
229
250
  width: float = 1.0,
230
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0)) -> None:
251
+ color: ColorType = WHITE) -> None:
231
252
  """Add a line instance to the batch."""
232
253
  self.instance_data.extend([*start, *end, width, *color])
233
254
  self.instance_count += 1
@@ -282,8 +303,21 @@ class ShapeRenderer:
282
303
  High-performance 2D shape renderer using SDF (Signed Distance Functions) and GPU shaders.
283
304
  Supports immediate mode, cached drawing, and batched rendering.
284
305
  """
306
+ ctx: ContextType
307
+ circle_instanced_prog: ProgramType
308
+ rect_instanced_prog: ProgramType
309
+ line_instanced_prog: ProgramType
310
+ circle_prog: ProgramType
311
+ rect_prog: ProgramType
312
+ line_prog: ProgramType
313
+ circle_vbo: BufferType
314
+ rect_vbo: BufferType
315
+ line_vbo: BufferType
316
+ circle_vao: VAOType
317
+ rect_vao: VAOType
318
+ line_vao: VAOType
285
319
 
286
- def __init__(self, ctx: moderngl.Context) -> None:
320
+ def __init__(self, ctx: ContextType) -> None:
287
321
  self.ctx = ctx
288
322
 
289
323
  # ===== INSTANCED Circle Shader (for high-performance batching) =====
@@ -697,16 +731,17 @@ class ShapeRenderer:
697
731
 
698
732
  # ========== CIRCLE ==========
699
733
 
700
- def _generate_circle_vertices(self, center: tuple[float, float], radius: float,
701
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
734
+ def _generate_circle_vertices(self, center: VectorType, radius: float,
735
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
702
736
  rotation: float = 0.0,
703
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
737
+ border_color: ColorType = (0.0, 0.0, 0.0, 0.0),
704
738
  border_width: float = 0.0,
705
739
  antialiasing: float = 1.0) -> list[float]:
706
740
  """Generate vertices for a circle (as a quad).
707
741
  Format: pos(2f), color(4f), radius(1f), border_color(4f), border_width(1f), aa(1f), center(2f)
708
742
  """
709
- cx, cy = center
743
+ # Handle VectorType input - convert to tuple if needed
744
+ cx, cy = center[0], center[1]
710
745
 
711
746
  # Expand for border and antialiasing
712
747
  expand = radius + border_width + antialiasing * 2
@@ -735,10 +770,10 @@ class ShapeRenderer:
735
770
 
736
771
  return vertices
737
772
 
738
- def draw_circle(self, center: tuple[float, float], radius: float,
739
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
773
+ def draw_circle(self, center: VectorType, radius: float,
774
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
740
775
  rotation: float = 0.0,
741
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
776
+ border_color: ColorType = (0.0, 0.0, 0.0, 0.0),
742
777
  border_width: float = 0.0,
743
778
  antialiasing: float = 1.0) -> None:
744
779
  """
@@ -763,10 +798,10 @@ class ShapeRenderer:
763
798
  set_pattr_value(self.circle_prog, 'resolution', self.ctx.viewport[2:])
764
799
  self.circle_vao.render(moderngl.TRIANGLES, vertices=6)
765
800
 
766
- def create_circle(self, center: tuple[float, float], radius: float,
767
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
801
+ def create_circle(self, center: VectorType, radius: float,
802
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
768
803
  rotation: float = 0.0,
769
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
804
+ border_color: ColorType = (0.0, 0.0, 0.0, 0.0),
770
805
  border_width: float = 0.0,
771
806
  antialiasing: float = 1.0) -> ShapeLabel:
772
807
  """Create a cached circle for repeated drawing."""
@@ -780,17 +815,18 @@ class ShapeRenderer:
780
815
 
781
816
  # ========== RECTANGLE ==========
782
817
 
783
- def _generate_rect_vertices(self, position: tuple[float, float], size: tuple[float, float],
784
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
818
+ def _generate_rect_vertices(self, position: VectorType, size: VectorType,
819
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
785
820
  rotation: float = 0.0,
786
821
  corner_radius: float = 0.0,
787
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
822
+ border_color: ColorType = (0.0, 0.0, 0.0, 0.0),
788
823
  border_width: float = 0.0,
789
824
  antialiasing: float = 1.0) -> list[float]:
790
825
  """Generate vertices for a rectangle.
791
826
  Format: pos(2f), color(4f), radius(1f), border_color(4f), border_width(1f), aa(1f), size(2f), local_pos(2f)
792
827
  """
793
- x, y = position
828
+ # Handle VectorType input - convert to tuple if needed
829
+ x, y = position[0], position[1]
794
830
  w, h = size
795
831
 
796
832
  # Center of rectangle
@@ -832,11 +868,11 @@ class ShapeRenderer:
832
868
 
833
869
  return vertices
834
870
 
835
- def draw_rect(self, position: tuple[float, float], size: tuple[float, float],
836
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
871
+ def draw_rect(self, position: VectorType, size: VectorType,
872
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
837
873
  rotation: float = 0.0,
838
874
  corner_radius: float = 0.0,
839
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
875
+ border_color: ColorType = (0.0, 0.0, 0.0, 0.0),
840
876
  border_width: float = 0.0,
841
877
  antialiasing: float = 1.0) -> None:
842
878
  """
@@ -862,11 +898,11 @@ class ShapeRenderer:
862
898
  set_pattr_value(self.rect_prog, 'resolution', self.ctx.viewport[2:])
863
899
  self.rect_vao.render(moderngl.TRIANGLES, vertices=6)
864
900
 
865
- def create_rect(self, position: tuple[float, float], size: tuple[float, float],
866
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
901
+ def create_rect(self, position: VectorType, size: VectorType,
902
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
867
903
  rotation: float = 0.0,
868
904
  corner_radius: float = 0.0,
869
- border_color: tuple[float, float, float, float] = (0.0, 0.0, 0.0, 0.0),
905
+ border_color: ColorType = (0.0, 0.0, 0.0, 0.0),
870
906
  border_width: float = 0.0,
871
907
  antialiasing: float = 1.0) -> ShapeLabel:
872
908
  """Create a cached rectangle for repeated drawing."""
@@ -880,12 +916,13 @@ class ShapeRenderer:
880
916
 
881
917
  # ========== LINES ==========
882
918
 
883
- def _generate_line_segment_vertices(self, start: tuple[float, float], end: tuple[float, float],
884
- width: float, color: tuple[float, float, float, float],
919
+ def _generate_line_segment_vertices(self, start: VectorType, end: VectorType,
920
+ width: float, color: ColorType,
885
921
  antialias: float = 1.0) -> list[float]:
886
922
  """Generate vertices for a line segment as a quad."""
887
- x1, y1 = start
888
- x2, y2 = end
923
+ # Handle VectorType input - convert to tuple if needed
924
+ x1, y1 = start[0], start[1]
925
+ x2, y2 = end[0], end[1]
889
926
 
890
927
  # Calculate perpendicular direction
891
928
  dx = x2 - x1
@@ -918,9 +955,9 @@ class ShapeRenderer:
918
955
 
919
956
  return vertices
920
957
 
921
- def draw_line(self, start: tuple[float, float], end: tuple[float, float],
958
+ def draw_line(self, start: VectorType, end: VectorType,
922
959
  width: float = 1.0,
923
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
960
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
924
961
  antialiasing: float = 1.0) -> None:
925
962
  """
926
963
  Draw a single line segment.
@@ -944,9 +981,9 @@ class ShapeRenderer:
944
981
  set_pattr_value(self.line_prog, 'resolution', self.ctx.viewport[2:])
945
982
  self.line_vao.render(moderngl.TRIANGLES, vertices=6)
946
983
 
947
- def draw_lines(self, points: np.ndarray | Sequence[tuple[float, float]],
984
+ def draw_lines(self, points: np.ndarray | Sequence[VectorType],
948
985
  width: float = 1.0,
949
- color: tuple[float, float, float, float] | np.ndarray = (1.0, 1.0, 1.0, 1.0),
986
+ color: ColorType | np.ndarray = (1.0, 1.0, 1.0, 1.0),
950
987
  antialiasing: float = 1.0,
951
988
  closed: bool = False) -> None:
952
989
  """
@@ -1003,9 +1040,9 @@ class ShapeRenderer:
1003
1040
  num_segments = (len(points_array) - 1) + (1 if closed else 0)
1004
1041
  self.line_vao.render(moderngl.TRIANGLES, vertices=num_segments * 6)
1005
1042
 
1006
- def create_line(self, start: tuple[float, float], end: tuple[float, float],
1043
+ def create_line(self, start: VectorType, end: VectorType,
1007
1044
  width: float = 1.0,
1008
- color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0),
1045
+ color: ColorType = (1.0, 1.0, 1.0, 1.0),
1009
1046
  antialiasing: float = 1.0) -> ShapeLabel:
1010
1047
  """Create a cached line for repeated drawing."""
1011
1048
  vertices = self._generate_line_segment_vertices(start, end, width, color, antialiasing)
@@ -1015,9 +1052,9 @@ class ShapeRenderer:
1015
1052
 
1016
1053
  return ShapeLabel(self.ctx, self.line_prog, vbo, 6, 'line')
1017
1054
 
1018
- def create_lines(self, points: np.ndarray | Sequence[tuple[float, float]],
1055
+ def create_lines(self, points: np.ndarray | Sequence[VectorType],
1019
1056
  width: float = 1.0,
1020
- color: tuple[float, float, float, float] | np.ndarray = (1.0, 1.0, 1.0, 1.0),
1057
+ color: ColorType | np.ndarray = (1.0, 1.0, 1.0, 1.0),
1021
1058
  antialiasing: float = 1.0,
1022
1059
  closed: bool = False) -> ShapeLabel:
1023
1060
  """Create a cached polyline for repeated drawing."""