molde 0.1.1__py3-none-any.whl → 0.1.2__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.
Files changed (55) hide show
  1. molde/__init__.py +6 -5
  2. molde/__main__.py +74 -63
  3. molde/actors/__init__.py +5 -4
  4. molde/actors/common_symbols_actor.py +148 -0
  5. molde/actors/ghost_actor.py +12 -12
  6. molde/actors/lines_actor.py +31 -31
  7. molde/actors/round_points_actor.py +7 -7
  8. molde/actors/square_points_actor.py +32 -32
  9. molde/colors/__init__.py +1 -1
  10. molde/colors/color.py +120 -120
  11. molde/colors/color_names.py +124 -124
  12. molde/interactor_styles/__init__.py +2 -2
  13. molde/interactor_styles/arcball_camera_style.py +288 -272
  14. molde/interactor_styles/box_selection_style.py +70 -70
  15. molde/main_window.ui +864 -0
  16. molde/pickers/__init__.py +2 -2
  17. molde/pickers/cell_area_picker.py +61 -61
  18. molde/pickers/cell_property_area_picker.py +84 -84
  19. molde/poly_data/__init__.py +19 -2
  20. molde/poly_data/arrows.py +54 -0
  21. molde/poly_data/complex_shapes.py +26 -0
  22. molde/poly_data/lines_data.py +23 -23
  23. molde/poly_data/simple_shapes.py +22 -0
  24. molde/poly_data/vertices_data.py +24 -24
  25. molde/render_widgets/__init__.py +2 -2
  26. molde/render_widgets/animated_render_widget.py +164 -164
  27. molde/render_widgets/common_render_widget.py +433 -433
  28. molde/stylesheets/__init__.py +119 -119
  29. molde/stylesheets/common.qss +16 -16
  30. molde/stylesheets/create_color_page.py +61 -61
  31. molde/stylesheets/mainwindow.ui +611 -611
  32. molde/stylesheets/qcheckbox.qss +18 -18
  33. molde/stylesheets/qinputs.qss +78 -78
  34. molde/stylesheets/qlayouts.qss +22 -22
  35. molde/stylesheets/qmenubar.qss +12 -12
  36. molde/stylesheets/qprogressbar.qss +11 -11
  37. molde/stylesheets/qpushbutton.qss +90 -90
  38. molde/stylesheets/qradiobutton.qss +30 -30
  39. molde/stylesheets/qscrollbar.qss +29 -29
  40. molde/stylesheets/qslider.qss +61 -61
  41. molde/stylesheets/qtablewidget.qss +27 -27
  42. molde/stylesheets/qtabwidget.qss +29 -29
  43. molde/stylesheets/qtoolbar.qss +62 -62
  44. molde/stylesheets/qtoolbuttons.qss +14 -14
  45. molde/stylesheets/qtreewidget.qss +25 -25
  46. molde/ui_files/messages/new_loading_window.ui +73 -0
  47. molde/utils/__init__.py +8 -8
  48. molde/utils/format_sequences.py +44 -44
  49. molde/utils/poly_data_utils.py +24 -24
  50. molde/utils/tree_info.py +52 -52
  51. molde/windows/loading_window.py +189 -0
  52. {molde-0.1.1.dist-info → molde-0.1.2.dist-info}/METADATA +4 -2
  53. molde-0.1.2.dist-info/RECORD +69 -0
  54. {molde-0.1.1.dist-info → molde-0.1.2.dist-info}/WHEEL +1 -1
  55. molde-0.1.1.dist-info/RECORD +0 -62
@@ -1,164 +1,164 @@
1
- from threading import Lock
2
- from time import time
3
- import numpy as np
4
- from pathlib import Path
5
- from PIL import Image
6
- import logging
7
-
8
- from .common_render_widget import CommonRenderWidget
9
-
10
-
11
- class AnimatedRenderWidget(CommonRenderWidget):
12
- def __init__(self, parent=None):
13
- super().__init__(parent)
14
-
15
- self.playing_animation = False
16
- self._animation_lock = Lock()
17
- self._animation_frame = 0
18
- self._animation_last_time = 0
19
- self._animation_total_frames = 30
20
- self._animation_fps = 30
21
- self._animation_cycles = 0
22
- self._animation_current_cycle = 0
23
- self._animation_timer = self.render_interactor.CreateRepeatingTimer(500)
24
- self.render_interactor.AddObserver("TimerEvent", self._animation_callback)
25
-
26
- def start_animation(self, fps=None, frames=None, cycles=None):
27
- if isinstance(fps, int | float):
28
- self._animation_fps = fps
29
-
30
- if isinstance(frames, int):
31
- self._animation_total_frames = frames
32
-
33
- if isinstance(cycles, int):
34
- self._animation_cycles = cycles
35
- self._animation_current_cycle = 0
36
- else:
37
- self._animation_cycles = 0
38
- self._animation_current_cycle = 0
39
-
40
- if self.playing_animation:
41
- return
42
-
43
- self.playing_animation = True
44
-
45
- def stop_animation(self):
46
- if not self.playing_animation:
47
- return
48
-
49
- if self._animation_timer is None:
50
- return
51
-
52
- self.playing_animation = False
53
-
54
- def toggle_animation(self):
55
- if self.playing_animation:
56
- self.stop_animation()
57
- else:
58
- self.start_animation()
59
-
60
- def _animation_callback(self, obj, event):
61
- """
62
- Common function with controls that are meaningfull to
63
- all kinds of animations.
64
- """
65
-
66
- if not self.playing_animation:
67
- return
68
-
69
- # Wait the rendering of the last frame
70
- # before starting a new one
71
- if self._animation_lock.locked():
72
- return
73
-
74
- # Only needed because vtk CreateRepeatingTimer(n)
75
- # does not work =/
76
- dt = time() - self._animation_last_time
77
- if (dt) < 1 / self._animation_fps:
78
- return
79
-
80
- if (self._animation_cycles != 0) and (self._animation_current_cycle >= self._animation_cycles):
81
- self.stop_animation()
82
- return
83
-
84
- if self._animation_frame == 0:
85
- self._animation_current_cycle += 1
86
-
87
- with self._animation_lock:
88
- self._animation_frame = (
89
- self._animation_frame + 1
90
- ) % self._animation_total_frames
91
- self.update_animation(self._animation_frame)
92
- self._animation_last_time = time()
93
-
94
- def update_animation(self, frame: int):
95
- raise NotImplementedError(
96
- 'The function "update_animation" was not implemented!'
97
- )
98
-
99
- def save_video(self, path: str | Path, n_loops=20):
100
- '''
101
- Saves a video of multiple cycles of the current animation.
102
- Supported formats are MP4, AVI, OGV, and WEBM.
103
- '''
104
- from moviepy.editor import ImageSequenceClip
105
-
106
- # Stop animation to prevent conflicts
107
- previous_state = self.playing_animation
108
- self.stop_animation()
109
-
110
- logging.info("Generating video frames...")
111
- images = list()
112
- for i in range(self._animation_total_frames):
113
- self.update_animation(i)
114
- screenshot = self.get_screenshot().resize([1920, 1080])
115
- images.append(screenshot)
116
- frames = [np.array(img) for img in images]
117
-
118
- # recover the playing animation status
119
- self.playing_animation = previous_state
120
-
121
- logging.info("Saving video to file...")
122
- clip = ImageSequenceClip(frames, self._animation_fps)
123
- clip = clip.loop(duration = clip.duration * n_loops)
124
- clip.write_videofile(str(path), preset="veryfast", logger=None)
125
-
126
- def save_animation(self, path: str | Path):
127
- '''
128
- Saves an animated image file of a animation cycle.
129
- Supported formats are WEBP and GIF.
130
-
131
- We strongly recomend you to use webp, because of the reduced
132
- file size and the superior visual quality.
133
- Despite that, gifs are usefull sometimes because of its popularity.
134
- '''
135
-
136
- path = Path(path)
137
- is_gif = path.suffix == ".gif"
138
-
139
- # Stop animation to prevent conflicts
140
- previous_state = self.playing_animation
141
- self.stop_animation()
142
-
143
- logging.info("Generating animation frames...")
144
- images:list[Image.Image] = list()
145
- for i in range(self._animation_total_frames):
146
- self.update_animation(i)
147
- screenshot = self.get_screenshot().convert("RGB").resize([1280, 720])
148
- if is_gif:
149
- screenshot = screenshot.quantize(method=Image.Quantize.FASTOCTREE, kmeans=2)
150
- images.append(screenshot)
151
-
152
- # recover the playing animation status
153
- self.playing_animation = previous_state
154
-
155
- logging.info("Saving animation to file...")
156
- images[0].save(
157
- path,
158
- save_all=True,
159
- append_images=images[1:],
160
- optimize=False,
161
- duration=self._animation_total_frames / self._animation_fps,
162
- loop=0,
163
- quality=90
164
- )
1
+ from threading import Lock
2
+ from time import time
3
+ import numpy as np
4
+ from pathlib import Path
5
+ from PIL import Image
6
+ import logging
7
+
8
+ from .common_render_widget import CommonRenderWidget
9
+
10
+
11
+ class AnimatedRenderWidget(CommonRenderWidget):
12
+ def __init__(self, parent=None):
13
+ super().__init__(parent)
14
+
15
+ self.playing_animation = False
16
+ self._animation_lock = Lock()
17
+ self._animation_frame = 0
18
+ self._animation_last_time = 0
19
+ self._animation_total_frames = 30
20
+ self._animation_fps = 30
21
+ self._animation_cycles = 0
22
+ self._animation_current_cycle = 0
23
+ self._animation_timer = self.render_interactor.CreateRepeatingTimer(500)
24
+ self.render_interactor.AddObserver("TimerEvent", self._animation_callback)
25
+
26
+ def start_animation(self, fps=None, frames=None, cycles=None):
27
+ if isinstance(fps, int | float):
28
+ self._animation_fps = fps
29
+
30
+ if isinstance(frames, int):
31
+ self._animation_total_frames = frames
32
+
33
+ if isinstance(cycles, int):
34
+ self._animation_cycles = cycles
35
+ self._animation_current_cycle = 0
36
+ else:
37
+ self._animation_cycles = 0
38
+ self._animation_current_cycle = 0
39
+
40
+ if self.playing_animation:
41
+ return
42
+
43
+ self.playing_animation = True
44
+
45
+ def stop_animation(self):
46
+ if not self.playing_animation:
47
+ return
48
+
49
+ if self._animation_timer is None:
50
+ return
51
+
52
+ self.playing_animation = False
53
+
54
+ def toggle_animation(self):
55
+ if self.playing_animation:
56
+ self.stop_animation()
57
+ else:
58
+ self.start_animation()
59
+
60
+ def _animation_callback(self, obj, event):
61
+ """
62
+ Common function with controls that are meaningfull to
63
+ all kinds of animations.
64
+ """
65
+
66
+ if not self.playing_animation:
67
+ return
68
+
69
+ # Wait the rendering of the last frame
70
+ # before starting a new one
71
+ if self._animation_lock.locked():
72
+ return
73
+
74
+ # Only needed because vtk CreateRepeatingTimer(n)
75
+ # does not work =/
76
+ dt = time() - self._animation_last_time
77
+ if (dt) < 1 / self._animation_fps:
78
+ return
79
+
80
+ if (self._animation_cycles != 0) and (self._animation_current_cycle >= self._animation_cycles):
81
+ self.stop_animation()
82
+ return
83
+
84
+ if self._animation_frame == 0:
85
+ self._animation_current_cycle += 1
86
+
87
+ with self._animation_lock:
88
+ self._animation_frame = (
89
+ self._animation_frame + 1
90
+ ) % self._animation_total_frames
91
+ self.update_animation(self._animation_frame)
92
+ self._animation_last_time = time()
93
+
94
+ def update_animation(self, frame: int):
95
+ raise NotImplementedError(
96
+ 'The function "update_animation" was not implemented!'
97
+ )
98
+
99
+ def save_video(self, path: str | Path, n_loops=20):
100
+ '''
101
+ Saves a video of multiple cycles of the current animation.
102
+ Supported formats are MP4, AVI, OGV, and WEBM.
103
+ '''
104
+ from moviepy.editor import ImageSequenceClip
105
+
106
+ # Stop animation to prevent conflicts
107
+ previous_state = self.playing_animation
108
+ self.stop_animation()
109
+
110
+ logging.info("Generating video frames...")
111
+ images = list()
112
+ for i in range(self._animation_total_frames):
113
+ self.update_animation(i)
114
+ screenshot = self.get_screenshot().resize([1920, 1080])
115
+ images.append(screenshot)
116
+ frames = [np.array(img) for img in images]
117
+
118
+ # recover the playing animation status
119
+ self.playing_animation = previous_state
120
+
121
+ logging.info("Saving video to file...")
122
+ clip = ImageSequenceClip(frames, self._animation_fps)
123
+ clip = clip.loop(duration = clip.duration * n_loops)
124
+ clip.write_videofile(str(path), preset="veryfast", logger=None)
125
+
126
+ def save_animation(self, path: str | Path):
127
+ '''
128
+ Saves an animated image file of a animation cycle.
129
+ Supported formats are WEBP and GIF.
130
+
131
+ We strongly recomend you to use webp, because of the reduced
132
+ file size and the superior visual quality.
133
+ Despite that, gifs are usefull sometimes because of its popularity.
134
+ '''
135
+
136
+ path = Path(path)
137
+ is_gif = path.suffix == ".gif"
138
+
139
+ # Stop animation to prevent conflicts
140
+ previous_state = self.playing_animation
141
+ self.stop_animation()
142
+
143
+ logging.info("Generating animation frames...")
144
+ images:list[Image.Image] = list()
145
+ for i in range(self._animation_total_frames):
146
+ self.update_animation(i)
147
+ screenshot = self.get_screenshot().convert("RGB").resize([1280, 720])
148
+ if is_gif:
149
+ screenshot = screenshot.quantize(method=Image.Quantize.FASTOCTREE, kmeans=2)
150
+ images.append(screenshot)
151
+
152
+ # recover the playing animation status
153
+ self.playing_animation = previous_state
154
+
155
+ logging.info("Saving animation to file...")
156
+ images[0].save(
157
+ path,
158
+ save_all=True,
159
+ append_images=images[1:],
160
+ optimize=False,
161
+ duration=self._animation_total_frames / self._animation_fps,
162
+ loop=0,
163
+ quality=90
164
+ )