Skip to content

Commit 322cc71

Browse files
committed
add grid snap
1 parent db44635 commit 322cc71

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

genesis/ext/pyrender/interaction/plugins/mesh_selector.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,29 @@ def __init__(
5858

5959
self.raycaster: ViewerRaycaster = ViewerRaycaster(self.scene)
6060

61+
def _snap_to_grid(self, position: Vec3) -> Vec3:
62+
"""
63+
Snap a position to the grid based on grid_snap settings.
64+
65+
Parameters
66+
----------
67+
position : Vec3
68+
The position to snap.
69+
70+
Returns
71+
-------
72+
Vec3
73+
The snapped position.
74+
"""
75+
snap_x, snap_y, snap_z = self.options.grid_snap
76+
77+
# Snap each axis if the snap value is non-negative
78+
x = round(position.x / snap_x) * snap_x if snap_x >= 0 else position.x
79+
y = round(position.y / snap_y) * snap_y if snap_y >= 0 else position.y
80+
z = round(position.z / snap_z) * snap_z if snap_z >= 0 else position.z
81+
82+
return Vec3.from_xyz(x, y, z)
83+
6184
@override
6285
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> EVENT_HANDLE_STATE:
6386
super().on_mouse_motion(x, y, dx, dy)
@@ -80,6 +103,9 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> EVENT_H
80103
local_pos = pose.inverse_transform_point(world_pos)
81104
local_normal = pose.inverse_transform_direction(world_normal)
82105

106+
# Apply grid snapping to local position
107+
local_pos = self._snap_to_grid(local_pos)
108+
83109
selected_point = SelectedPoint(
84110
link=link,
85111
local_position=local_pos,
@@ -103,14 +129,15 @@ def on_draw(self) -> None:
103129

104130
closest_hit = self.raycaster.cast_ray(mouse_ray.origin.v, mouse_ray.direction.v)
105131
if closest_hit.is_hit:
132+
snap_pos = self._snap_to_grid(closest_hit.position)
106133
# Draw hover preview
107134
self.scene.draw_debug_sphere(
108-
closest_hit.position.v,
135+
snap_pos.v,
109136
self.options.sphere_radius,
110137
self.options.hover_color,
111138
)
112139
self.scene.draw_debug_arrow(
113-
closest_hit.position.v,
140+
snap_pos.v,
114141
closest_hit.normal.v * 0.1,
115142
self.options.sphere_radius / 2,
116143
self.options.hover_color,

genesis/options/viewer_plugins.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ class MeshPointSelectorPlugin(ViewerPlugin):
3131
The color of the sphere used to visualize selected points.
3232
hover_color : tuple
3333
The color of the sphere used to visualize the point and normal when hovering over a mesh.
34+
grid_snap : tuple[float, float, float]
35+
Grid snap spacing for each axis (x, y, z). Any negative value disables snapping for that axis.
36+
Default is (-1.0, -1.0, -1.0) which means no snapping.
3437
"""
3538

3639
sphere_radius: float = 0.005
37-
sphere_color: tuple = (1.0, 0.0, 0.0, 1.0)
38-
hover_color: tuple = (1.0, 0.0, 0.0, 1.0)
40+
sphere_color: tuple = (0.1, 0.3, 1.0, 1.0)
41+
hover_color: tuple = (0.3, 0.5, 1.0, 1.0)
42+
grid_snap: tuple[float, float, float] = (-1.0, -1.0, -1.0)
3943
output_file: str = "selected_points.csv"

genesis/options/vis.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import genesis as gs
44

55
from .options import Options
6+
from .viewer_plugins import ViewerPlugin
67

78

89
class ViewerOptions(Options):
@@ -33,17 +34,19 @@ class ViewerOptions(Options):
3334
The up vector of the camera's extrinsic pose.
3435
camera_fov : float
3536
The field of view (in degrees) of the camera.
37+
viewer_plugin : ViewerPluginOptions | None
38+
Optional viewer plugin that adds interactive functionality to the viewer.
3639
"""
3740

38-
res: Optional[tuple] = None
39-
run_in_thread: Optional[bool] = None
41+
res: tuple | None = None
42+
run_in_thread: bool | None = None
4043
refresh_rate: int = 60
41-
max_FPS: Optional[int] = 60
44+
max_FPS: int | None = 60
4245
camera_pos: tuple = (3.5, 0.5, 2.5)
4346
camera_lookat: tuple = (0.0, 0.0, 0.5)
4447
camera_up: tuple = (0.0, 0.0, 1.0)
4548
camera_fov: float = 40
46-
enable_interaction: bool = False
49+
viewer_plugin: ViewerPlugin | None = None
4750

4851

4952
class VisOptions(Options):
@@ -139,7 +142,7 @@ def __init__(self, **data):
139142
f"Unsupported `render_particle_as`: {self.render_particle_as}, must be one of ['sphere', 'tet']"
140143
)
141144

142-
if not self.n_rendered_envs is None:
145+
if self.n_rendered_envs is not None:
143146
gs.logger.warning(
144147
"Viewer option 'n_rendered_envs' is deprecated and will be removed in future release. Please use "
145148
"'rendered_envs_idx' instead."

0 commit comments

Comments
 (0)