From 8925722e541d196aacc278b73f0ab13f5b5a03a5 Mon Sep 17 00:00:00 2001 From: jdrotleff <151064457+jpd-de@users.noreply.github.com> Date: Thu, 6 Jun 2024 08:57:46 +0200 Subject: [PATCH 01/11] Added Step Back and Restart feature This allows to jump back to the last frame or restart the visualization with a button. Name changes: Step: >> Step back: << --- znvis/visualizer/visualizer.py | 47 +++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index ddfbe62..68d3a29 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -128,8 +128,9 @@ def _initialize_app(self): self.vis.reset_camera_to_default() # Add actions to the visualizer. - self.vis.add_action("Step", self._update_particles) + self.vis.add_action("<<", self._update_particles_back) self.vis.add_action("Play", self._continuous_trajectory) + self.vis.add_action(">>", self._update_particles) self.vis.add_action("Export Scene", self._export_scene) self.vis.add_action("Screenshot", self._take_screenshot) self.vis.add_action("Export Video", self._export_video) @@ -553,6 +554,50 @@ def _update_particles(self, visualizer=None, step: int = None): visualizer.post_redraw() # re-draw the window. + def _update_particles_back(self, visualizer=None, step: int = None): + """ + Update the positions of the particles one step back (rewind-feature) + + Parameters + ---------- + step : int + Step to update to. + + Returns + ------- + Updates the positions of the particles in the box. + """ + if visualizer is None: + visualizer = self.vis + if step is None: + if self.counter == self.number_of_steps - 1: + self.counter = self.number_of_steps - 1 + else: + self.counter -= 1 + step = self.counter + + self._draw_particles(visualizer=visualizer) # draw the particles. + + # draw the vector field if it exists. + if self.vector_field is not None: + self._draw_vector_field(visualizer=visualizer) + + visualizer.post_redraw() # re-draw the window. + + def _restart_trajectory(self, visualizer=None): + if visualizer is None: + visualizer = self.vis + self.counter = 0 + + self._draw_particles(visualizer=visualizer) # draw the particles. + + # draw the vector field if it exists. + if self.vector_field is not None: + self._draw_vector_field(visualizer=visualizer) + + visualizer.post_redraw() # re-draw the window. + + def run_visualization(self): """ Run the visualization. From 21bacd8b7b4eac26f74bfe19fb76536323e045a3 Mon Sep 17 00:00:00 2001 From: jdrotleff <151064457+jpd-de@users.noreply.github.com> Date: Mon, 10 Jun 2024 09:26:32 +0200 Subject: [PATCH 02/11] Added fast forward/Slow-Mo Also added bugfix for number_of_steps --- znvis/visualizer/visualizer.py | 174 +++++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 30 deletions(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 68d3a29..06ddefe 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -95,7 +95,11 @@ def __init__( self.bounding_box = bounding_box() if bounding_box else None if number_of_steps is None: - number_of_steps = len(particles[0].position) + len_list = [] + for particle in particles: + if not particle.static: + len_list.append(len(particle.position)) + number_of_steps = min(len_list) self.number_of_steps = number_of_steps self.output_folder = pathlib.Path(output_folder).resolve() @@ -103,6 +107,7 @@ def __init__( self.video_format = video_format self.keep_frames = keep_frames self.renderer = renderer + self.play_speed = 1 self.obj_folder = self.output_folder / "obj_files" @@ -131,11 +136,15 @@ def _initialize_app(self): self.vis.add_action("<<", self._update_particles_back) self.vis.add_action("Play", self._continuous_trajectory) self.vis.add_action(">>", self._update_particles) + self.vis.add_action(">>>", self._toggle_play_speed) + self.vis.add_action("Slow", self._toggle_slowmotion) + self.vis.add_action("Restart", self._restart_trajectory) self.vis.add_action("Export Scene", self._export_scene) self.vis.add_action("Screenshot", self._take_screenshot) self.vis.add_action("Export Video", self._export_video) self.vis.add_action("Export Mesh Trajectory", self._export_mesh_trajectory) + # Add the visualizer to the app. self.app.add_window(self.vis) @@ -272,18 +281,35 @@ def _take_screenshot(self, vis): old_state = self.interrupt # get old state self.interrupt = 0 # stop live feed if running. mesh_dict = {} - mesh_center = [] + + if self.vector_field is not None: + for item in self.vector_field: + if item.static: + mesh_dict[item.name] = { + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } + else: + mesh_dict[item.name] = { + "mesh": item.mesh_list[self.counter], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } + for item in self.particles: - mesh_dict[item.name] = { - "mesh": item.mesh_list[self.counter], - "bsdf": item.mesh.material.mitsuba_bsdf, - "material": item.mesh.o3d_material, + if item.static: + mesh_dict[item.name] = { + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, } - mesh_center.append( - item.mesh_list[self.counter] - .get_axis_aligned_bounding_box() - .get_center() - ) + else: + mesh_dict[item.name] = { + "mesh": item.mesh_list[self.counter], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } view_matrix = vis.scene.camera.get_view_matrix() @@ -347,10 +373,12 @@ def _draw_particles(self, visualizer=None, initial: bool = False): visualizer.add_geometry("Box", self.bounding_box) else: for i, item in enumerate(self.particles): - visualizer.remove_geometry(item.name) - visualizer.add_geometry( - item.name, item.mesh_list[self.counter], item.mesh.o3d_material - ) + if not item.static: + print(item.name) + visualizer.remove_geometry(item.name) + visualizer.add_geometry( + item.name, item.mesh_list[self.counter], item.mesh.o3d_material + ) def _draw_vector_field(self, visualizer=None, initial: bool = False): @@ -377,10 +405,11 @@ def _draw_vector_field(self, visualizer=None, initial: bool = False): ) else: for i, item in enumerate(self.vector_field): - visualizer.remove_geometry(item.name) - visualizer.add_geometry( - item.name, item.mesh_list[self.counter], item.mesh.o3d_material - ) + if not item.static: + visualizer.remove_geometry(item.name) + visualizer.add_geometry( + item.name, item.mesh_list[self.counter], item.mesh.o3d_material + ) def _continuous_trajectory(self, vis): """ @@ -396,6 +425,20 @@ def _continuous_trajectory(self, vis): else: threading.Thread(target=self._run_trajectory).start() + def _continuous_trajectory_backwards(self, vis): + """ + Button command for running the simulation in the visualizer backwards. + + Parameters + ---------- + vis : visualizer + Object passed during the callback. + """ + if self.interrupt == 1: + self._pause_run(vis) + else: + threading.Thread(target=self._run_trajectory_backwards).start() + def _record_trajectory(self): """ Record the trajectory. @@ -416,12 +459,34 @@ def save_callable(): """ mesh_dict = {} + if self.vector_field is not None: + for item in self.vector_field: + if item.static: + mesh_dict[item.name] = { + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } + else: + mesh_dict[item.name] = { + "mesh": item.mesh_list[self.counter], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } + for item in self.particles: - mesh_dict[item.name] = { - "mesh": item.mesh_list[self.counter], - "bsdf": item.mesh.material.mitsuba_bsdf, - "material": item.mesh.o3d_material, + if item.static: + mesh_dict[item.name] = { + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, } + else: + mesh_dict[item.name] = { + "mesh": item.mesh_list[self.counter], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } view_matrix = self.vis.scene.camera.get_view_matrix() self.renderer.render_mesh_objects( @@ -473,10 +538,16 @@ def save_callable(): Function to be called on thread to save image. """ for i, item in enumerate(self.particles): - if i == 0: - mesh = item.mesh_list[self.counter] + if item.static: + if i == 0: + mesh = item.mesh_list[0] + else: + mesh += item.mesh_list[0] else: - mesh += item.mesh_list[self.counter] + if i == 0: + mesh = item.mesh_list[self.counter] + else: + mesh += item.mesh_list[self.counter] o3d.io.write_triangle_mesh( (self.obj_folder / f"export_mesh_{self.counter}.ply").as_posix(), mesh @@ -514,7 +585,7 @@ def _run_trajectory(self): """ self.interrupt = 1 # set global run state. while self.counter < self.number_of_steps: - time.sleep(1 / self.frame_rate) + time.sleep(1 / (self.frame_rate * self.play_speed)) o3d.visualization.gui.Application.instance.post_to_main_thread( self.vis, self._update_particles ) @@ -524,6 +595,7 @@ def _run_trajectory(self): self.interrupt = 0 # reset global state. + def _update_particles(self, visualizer=None, step: int = None): """ Update the positions of the particles. @@ -570,12 +642,11 @@ def _update_particles_back(self, visualizer=None, step: int = None): if visualizer is None: visualizer = self.vis if step is None: - if self.counter == self.number_of_steps - 1: + if self.counter == 0: self.counter = self.number_of_steps - 1 else: self.counter -= 1 step = self.counter - self._draw_particles(visualizer=visualizer) # draw the particles. # draw the vector field if it exists. @@ -584,6 +655,7 @@ def _update_particles_back(self, visualizer=None, step: int = None): visualizer.post_redraw() # re-draw the window. + def _restart_trajectory(self, visualizer=None): if visualizer is None: visualizer = self.vis @@ -597,7 +669,49 @@ def _restart_trajectory(self, visualizer=None): visualizer.post_redraw() # re-draw the window. - + def _toggle_play_speed(self, visualizer=None): + """ + Toggle the play speed from 1 to 2 to 4 to 8 and back to 1. + + """ + if self.play_speed == 1: + self.play_speed = 2 + elif self.play_speed == 2: + self.play_speed = 4 + elif self.play_speed == 4: + self.play_speed = 8 + else: + self.play_speed = 1 + + def _toggle_play_speed_back(self, visualizer=None): + """ + Toggle the play speed from 1 to 2 to 4 to 8 and back to 1. + """ + + self._run_trajectory_backwards() + if self.play_speed == 1: + self.play_speed = 2 + elif self.play_speed == 2: + self.play_speed = 4 + elif self.play_speed == 4: + self.play_speed = 8 + else: + self.play_speed = 1 + + def _toggle_slowmotion(self, visualizer=None): + """ + Toggle the play speed from 1 to 1/2 to 1/4 to 1/8 and back to 1 + """ + if self.play_speed >= 1: + self.play_speed = 1/2 + elif self.play_speed == 1/2: + self.play_speed = 1/4 + elif self.play_speed == 1/4: + self.play_speed = 1/8 + else: + self.play_speed = 1 + + def run_visualization(self): """ Run the visualization. From e36aab59313ffc7b161e01b3719856b305aa1008 Mon Sep 17 00:00:00 2001 From: jpd-de Date: Mon, 10 Jun 2024 13:45:21 +0200 Subject: [PATCH 03/11] Removed forgotten print statement --- znvis/visualizer/visualizer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 06ddefe..93d1864 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -374,7 +374,6 @@ def _draw_particles(self, visualizer=None, initial: bool = False): else: for i, item in enumerate(self.particles): if not item.static: - print(item.name) visualizer.remove_geometry(item.name) visualizer.add_geometry( item.name, item.mesh_list[self.counter], item.mesh.o3d_material From 57c6b07da207c2679d5f95b117fdea427a8e0ba6 Mon Sep 17 00:00:00 2001 From: jdrotleff <151064457+jpd-de@users.noreply.github.com> Date: Fri, 14 Jun 2024 12:15:58 +0200 Subject: [PATCH 04/11] Fixed number_of_steps bug for static meshes Adapted spacing as well --- znvis/visualizer/visualizer.py | 63 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 93d1864..2d4895f 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -144,7 +144,6 @@ def _initialize_app(self): self.vis.add_action("Export Video", self._export_video) self.vis.add_action("Export Mesh Trajectory", self._export_mesh_trajectory) - # Add the visualizer to the app. self.app.add_window(self.vis) @@ -281,29 +280,29 @@ def _take_screenshot(self, vis): old_state = self.interrupt # get old state self.interrupt = 0 # stop live feed if running. mesh_dict = {} - + if self.vector_field is not None: for item in self.vector_field: if item.static: mesh_dict[item.name] = { - "mesh": item.mesh_list[0], - "bsdf": item.mesh.material.mitsuba_bsdf, - "material": item.mesh.o3d_material, - } + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, } - + for item in self.particles: if item.static: mesh_dict[item.name] = { "mesh": item.mesh_list[0], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, - } + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], @@ -379,7 +378,6 @@ def _draw_particles(self, visualizer=None, initial: bool = False): item.name, item.mesh_list[self.counter], item.mesh.o3d_material ) - def _draw_vector_field(self, visualizer=None, initial: bool = False): """ Draw the vector field on the visualizer. @@ -396,7 +394,7 @@ def _draw_vector_field(self, visualizer=None, initial: bool = False): """ if visualizer is None: visualizer = self.vis - + if initial: for i, item in enumerate(self.vector_field): visualizer.add_geometry( @@ -462,24 +460,24 @@ def save_callable(): for item in self.vector_field: if item.static: mesh_dict[item.name] = { - "mesh": item.mesh_list[0], - "bsdf": item.mesh.material.mitsuba_bsdf, - "material": item.mesh.o3d_material, - } + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, } - + for item in self.particles: if item.static: mesh_dict[item.name] = { "mesh": item.mesh_list[0], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, - } + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], @@ -594,7 +592,6 @@ def _run_trajectory(self): self.interrupt = 0 # reset global state. - def _update_particles(self, visualizer=None, step: int = None): """ Update the positions of the particles. @@ -621,7 +618,7 @@ def _update_particles(self, visualizer=None, step: int = None): # draw the vector field if it exists. if self.vector_field is not None: - self._draw_vector_field(visualizer=visualizer) + self._draw_vector_field(visualizer=visualizer) visualizer.post_redraw() # re-draw the window. @@ -650,11 +647,10 @@ def _update_particles_back(self, visualizer=None, step: int = None): # draw the vector field if it exists. if self.vector_field is not None: - self._draw_vector_field(visualizer=visualizer) + self._draw_vector_field(visualizer=visualizer) visualizer.post_redraw() # re-draw the window. - def _restart_trajectory(self, visualizer=None): if visualizer is None: visualizer = self.vis @@ -664,14 +660,14 @@ def _restart_trajectory(self, visualizer=None): # draw the vector field if it exists. if self.vector_field is not None: - self._draw_vector_field(visualizer=visualizer) + self._draw_vector_field(visualizer=visualizer) visualizer.post_redraw() # re-draw the window. def _toggle_play_speed(self, visualizer=None): - """ + """ Toggle the play speed from 1 to 2 to 4 to 8 and back to 1. - + """ if self.play_speed == 1: self.play_speed = 2 @@ -681,12 +677,12 @@ def _toggle_play_speed(self, visualizer=None): self.play_speed = 8 else: self.play_speed = 1 - + def _toggle_play_speed_back(self, visualizer=None): - """ + """ Toggle the play speed from 1 to 2 to 4 to 8 and back to 1. """ - + self._run_trajectory_backwards() if self.play_speed == 1: self.play_speed = 2 @@ -696,21 +692,20 @@ def _toggle_play_speed_back(self, visualizer=None): self.play_speed = 8 else: self.play_speed = 1 - + def _toggle_slowmotion(self, visualizer=None): - """ + """ Toggle the play speed from 1 to 1/2 to 1/4 to 1/8 and back to 1 """ if self.play_speed >= 1: - self.play_speed = 1/2 - elif self.play_speed == 1/2: - self.play_speed = 1/4 - elif self.play_speed == 1/4: - self.play_speed = 1/8 + self.play_speed = 1 / 2 + elif self.play_speed == 1 / 2: + self.play_speed = 1 / 4 + elif self.play_speed == 1 / 4: + self.play_speed = 1 / 8 else: self.play_speed = 1 - def run_visualization(self): """ Run the visualization. From eec33b61c18bf89633fd20cda758a3fdb0bb2f60 Mon Sep 17 00:00:00 2001 From: jdrotleff <151064457+jpd-de@users.noreply.github.com> Date: Fri, 14 Jun 2024 12:36:54 +0200 Subject: [PATCH 05/11] Added working bugfix --- znvis/visualizer/visualizer.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 2d4895f..21e3ae4 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -99,8 +99,11 @@ def __init__( for particle in particles: if not particle.static: len_list.append(len(particle.position)) - number_of_steps = min(len_list) - self.number_of_steps = number_of_steps + + if len_list == []: + self.number_of_steps = 1 + else: + self.number_of_steps = min(len_list) self.output_folder = pathlib.Path(output_folder).resolve() self.frame_folder = self.output_folder / "video_frames" From 253d9400ad83c5c1fb09f79ecdb4da2dd242c2b3 Mon Sep 17 00:00:00 2001 From: phohenberger Date: Mon, 3 Jun 2024 14:57:38 +0200 Subject: [PATCH 06/11] Add static rendering --- znvis/particle/particle.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/znvis/particle/particle.py b/znvis/particle/particle.py index 3540880..d75f9c1 100644 --- a/znvis/particle/particle.py +++ b/znvis/particle/particle.py @@ -51,6 +51,10 @@ class Particle: Director tensor of the shape (n_confs, n_particles, n_dims) mesh_list : list A list of mesh objects, one for each time step. + static : bool (default=False) + If true, only render the mesh once at initialization. Be careful + as this changes the shape of the required position and director + to (n_particles, n_dims) smoothing : bool (default=False) If true, apply smoothing to each mesh object as it is rendered. This will slow down the initial construction of the mesh objects @@ -64,7 +68,7 @@ class Particle: force: np.ndarray = None director: np.ndarray = None mesh_list: typing.List[Mesh] = None - + static: bool = False smoothing: bool = False def _create_mesh(self, position, director): @@ -105,13 +109,21 @@ def construct_mesh_list(self): """ self.mesh_list = [] try: - # n_particles = int(self.position.shape[1]) - n_time_steps = int(len(self.position)) + if not self.static: + n_particles = int(self.position.shape[1]) + n_time_steps = int(self.position.shape[0]) + else: + n_particles = int(self.position.shape[0]) + n_time_steps = 1 + self.position = self.position[np.newaxis, :, :] + if self.director is not None: + self.director = self.director[np.newaxis, :, :] + except ValueError: raise ValueError("There is no data for these particles.") for i in track(range(n_time_steps), description=f"Building {self.name} Mesh"): - for j in range(np.shape(self.position[i])[0]): + for j in range(n_particles): if j == 0: if self.director is not None: mesh = self._create_mesh( From 2ecb9dd3e1c484f8e14f8f53596fe1d700f87373 Mon Sep 17 00:00:00 2001 From: phohenberger Date: Mon, 3 Jun 2024 16:53:33 +0200 Subject: [PATCH 07/11] Fix record video and add static vector field --- znvis/particle/vector_field.py | 17 ++++++++++++++--- znvis/visualizer/visualizer.py | 17 +++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/znvis/particle/vector_field.py b/znvis/particle/vector_field.py index 871a3b6..a86a6c9 100644 --- a/znvis/particle/vector_field.py +++ b/znvis/particle/vector_field.py @@ -47,6 +47,10 @@ class VectorField: Direction tensor of the shape (n_steps, n_vectors, n_dims) mesh_list : list A list of mesh objects, one for each time step. + static : bool (default=False) + If true, only render the mesh once at initialization. Be careful + as this changes the shape of the required position and direction + to (n_particles, n_dims) smoothing : bool (default=False) If true, apply smoothing to each mesh object as it is rendered. This will slow down the initial construction of the mesh objects @@ -58,7 +62,7 @@ class VectorField: position: np.ndarray = None direction: np.ndarray = None mesh_list: typing.List[Arrow] = None - + static: bool = False smoothing: bool = False def _create_mesh(self, position: np.ndarray, direction: np.ndarray): @@ -97,8 +101,15 @@ def construct_mesh_list(self): """ self.mesh_list = [] try: - n_particles = int(self.position.shape[1]) - n_time_steps = int(self.position.shape[0]) + if not self.static: + n_particles = int(self.position.shape[1]) + n_time_steps = int(self.position.shape[0]) + else: + n_particles = int(self.position.shape[0]) + n_time_steps = 1 + self.position = self.position[np.newaxis, :, :] + self.direction = self.direction[np.newaxis, :, :] + except ValueError: raise ValueError("There is no data for this vector field.") diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 21e3ae4..97f3948 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -410,6 +410,11 @@ def _draw_vector_field(self, visualizer=None, initial: bool = False): visualizer.add_geometry( item.name, item.mesh_list[self.counter], item.mesh.o3d_material ) + if not item.static: + visualizer.remove_geometry(item.name) + visualizer.add_geometry( + item.name, item.mesh_list[self.counter], item.mesh.o3d_material + ) def _continuous_trajectory(self, vis): """ @@ -463,24 +468,24 @@ def save_callable(): for item in self.vector_field: if item.static: mesh_dict[item.name] = { - "mesh": item.mesh_list[0], - "bsdf": item.mesh.material.mitsuba_bsdf, - "material": item.mesh.o3d_material, - } + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, } - + for item in self.particles: if item.static: mesh_dict[item.name] = { "mesh": item.mesh_list[0], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, - } + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], From 6014a732dac5d87b478fa34dcca98d3250f48884 Mon Sep 17 00:00:00 2001 From: Paul Hohenberger <49005843+phohenberger@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:58:08 +0200 Subject: [PATCH 08/11] Fix screen shot and remove old code --- znvis/visualizer/visualizer.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 97f3948..68310bb 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -283,29 +283,29 @@ def _take_screenshot(self, vis): old_state = self.interrupt # get old state self.interrupt = 0 # stop live feed if running. mesh_dict = {} - + if self.vector_field is not None: for item in self.vector_field: if item.static: mesh_dict[item.name] = { - "mesh": item.mesh_list[0], - "bsdf": item.mesh.material.mitsuba_bsdf, - "material": item.mesh.o3d_material, - } + "mesh": item.mesh_list[0], + "bsdf": item.mesh.material.mitsuba_bsdf, + "material": item.mesh.o3d_material, + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, } - + for item in self.particles: if item.static: mesh_dict[item.name] = { "mesh": item.mesh_list[0], "bsdf": item.mesh.material.mitsuba_bsdf, "material": item.mesh.o3d_material, - } + } else: mesh_dict[item.name] = { "mesh": item.mesh_list[self.counter], From e6d661766efe256f7c63c48af5da46eb74734113 Mon Sep 17 00:00:00 2001 From: Paul Hohenberger <49005843+phohenberger@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:38:24 +0200 Subject: [PATCH 09/11] Skip vector of length zero --- znvis/particle/vector_field.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/znvis/particle/vector_field.py b/znvis/particle/vector_field.py index a86a6c9..3c1e9a2 100644 --- a/znvis/particle/vector_field.py +++ b/znvis/particle/vector_field.py @@ -113,10 +113,16 @@ def construct_mesh_list(self): except ValueError: raise ValueError("There is no data for this vector field.") + new_mesh = True + for i in track(range(n_time_steps), description=f"Building {self.name} Mesh"): for j in range(n_particles): - if j == 0: - mesh = self._create_mesh(self.position[i][j], self.direction[i][j]) - else: - mesh += self._create_mesh(self.position[i][j], self.direction[i][j]) + if np.max(self.direction[i][j]) > 0: # ignore vectors with length zero + if new_mesh is False: + mesh += self._create_mesh(self.position[i][j], self.direction[i][j]) + else: + mesh = self._create_mesh(self.position[i][j], self.direction[i][j]) + new_mesh = False + new_mesh = True + self.mesh_list.append(mesh) From 8914bde427db9dc2f616d129954e4d32c74adf82 Mon Sep 17 00:00:00 2001 From: jdrotleff <151064457+jpd-de@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:05:27 +0200 Subject: [PATCH 10/11] Removed merge process artifact --- znvis/visualizer/visualizer.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index 68310bb..cbd3e53 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -410,11 +410,6 @@ def _draw_vector_field(self, visualizer=None, initial: bool = False): visualizer.add_geometry( item.name, item.mesh_list[self.counter], item.mesh.o3d_material ) - if not item.static: - visualizer.remove_geometry(item.name) - visualizer.add_geometry( - item.name, item.mesh_list[self.counter], item.mesh.o3d_material - ) def _continuous_trajectory(self, vis): """ From f19de0dd0e2e5cbe1c3c0862840b8d76bb43d370 Mon Sep 17 00:00:00 2001 From: jdrotleff <151064457+jpd-de@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:32:39 +0200 Subject: [PATCH 11/11] Toggle play direction + fixed export scene for static meshes --- znvis/visualizer/visualizer.py | 56 ++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/znvis/visualizer/visualizer.py b/znvis/visualizer/visualizer.py index cbd3e53..ab15302 100644 --- a/znvis/visualizer/visualizer.py +++ b/znvis/visualizer/visualizer.py @@ -111,6 +111,7 @@ def __init__( self.keep_frames = keep_frames self.renderer = renderer self.play_speed = 1 + self.do_rewind = False self.obj_folder = self.output_folder / "obj_files" @@ -136,10 +137,12 @@ def _initialize_app(self): self.vis.reset_camera_to_default() # Add actions to the visualizer. + self.vis.add_action("<<<", self._toggle_play_speed_back) self.vis.add_action("<<", self._update_particles_back) self.vis.add_action("Play", self._continuous_trajectory) self.vis.add_action(">>", self._update_particles) self.vis.add_action(">>>", self._toggle_play_speed) + self.vis.add_action("Toggle Direction", self._toogle_play_direction) self.vis.add_action("Slow", self._toggle_slowmotion) self.vis.add_action("Restart", self._restart_trajectory) self.vis.add_action("Export Scene", self._export_scene) @@ -175,6 +178,7 @@ def _export_video(self, vis): ------- Saves a video locally. """ + self.do_rewind = False self.interrupt = 0 # stop live feed if running. # Create temporary directory @@ -253,9 +257,20 @@ def _export_scene(self, vis): """ old_state = self.interrupt # get old state self.interrupt = 0 # stop live feed if running. + created_mesh = False for i, item in enumerate(self.particles): - if i == 0: + if item.static: + if i == 0 and not created_mesh: + mesh = item.mesh_list[0] + created_mesh = True + elif i == 0 and created_mesh: + mesh += item.mesh_list[0] + else: + continue + + if i == 0 and not created_mesh: mesh = item.mesh_list[self.counter] + created_mesh = True else: mesh += item.mesh_list[self.counter] @@ -420,25 +435,12 @@ def _continuous_trajectory(self, vis): vis : visualizer Object passed during the callback. """ + self.do_rewind = False if self.interrupt == 1: self._pause_run(vis) else: threading.Thread(target=self._run_trajectory).start() - def _continuous_trajectory_backwards(self, vis): - """ - Button command for running the simulation in the visualizer backwards. - - Parameters - ---------- - vis : visualizer - Object passed during the callback. - """ - if self.interrupt == 1: - self._pause_run(vis) - else: - threading.Thread(target=self._run_trajectory_backwards).start() - def _record_trajectory(self): """ Record the trajectory. @@ -616,6 +618,11 @@ def _update_particles(self, visualizer=None, step: int = None): else: self.counter += 1 step = self.counter + if self.do_rewind == True: + if self.counter <= 1: + self.counter = self.number_of_steps - 2 + else: + self.counter -= 2 self._draw_particles(visualizer=visualizer) # draw the particles. @@ -654,6 +661,16 @@ def _update_particles_back(self, visualizer=None, step: int = None): visualizer.post_redraw() # re-draw the window. + def _toogle_play_direction(self, visualizer=None): + """ + Reverts the direction of play. + + Returns + ------- + Rewinds the trajectory. + """ + self.do_rewind = not self.do_rewind + def _restart_trajectory(self, visualizer=None): if visualizer is None: visualizer = self.vis @@ -672,6 +689,10 @@ def _toggle_play_speed(self, visualizer=None): Toggle the play speed from 1 to 2 to 4 to 8 and back to 1. """ + if self.do_rewind == True: + self.do_rewind = False + self.play_speed = 1 + if self.play_speed == 1: self.play_speed = 2 elif self.play_speed == 2: @@ -685,8 +706,11 @@ def _toggle_play_speed_back(self, visualizer=None): """ Toggle the play speed from 1 to 2 to 4 to 8 and back to 1. """ + if self.do_rewind == False: + self.play_speed = 1 + + self.do_rewind = True - self._run_trajectory_backwards() if self.play_speed == 1: self.play_speed = 2 elif self.play_speed == 2: