forked from napari/napari
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinteractive_move_point_3d.py
101 lines (83 loc) · 2.58 KB
/
interactive_move_point_3d.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""
Interactive move point
======================
3D click and drag interactivity demo
"""
from copy import copy
import numpy as np
import napari
from napari.utils.geometry import project_points_onto_plane
# Create viewer, point to move and bounding box
viewer = napari.Viewer(ndisplay=3)
bounding_box_data = [
[-1, -1, -1],
[-1, -1, 1],
[-1, 1, -1],
[-1, 1, 1],
[1, -1, -1],
[1, -1, 1],
[1, 1, -1],
[1, 1, 1]
]
bounding_box_layer = viewer.add_points(
bounding_box_data,
name='bounding box',
face_color='green',
size=0.2,
edge_width=0
)
point_layer = viewer.add_points(
[0, 0, 0],
name='point',
face_color='magenta',
size=0.2,
edge_width=0
)
@point_layer.mouse_drag_callbacks.append
def drag_along_camera_plane(layer, event):
# early exit if shift isn't held
if not 'Shift' in event.modifiers:
return
# disable interactivity during this drag event to fix the view direction
layer.interactive = False
# store start position of point
original_position = copy(point_layer.data[0])
yield
while event.type == 'mouse_move':
# Calculate click position in data coords
point_to_project = np.asarray(layer.world_to_data(event.position))[
list(event.dims_displayed)
]
# Calculate view direction in data coordinates
# this view direction, together with the click position, form a plane
# parallel to the canvas in data coordinates.
view_direction_data = np.asarray(layer._world_to_data_ray(
list(event.view_direction)
))[event.dims_displayed]
# Project click position onto plane
projected_position = project_point_onto_plane(
point=point_to_project,
plane_point=original_position,
plane_normal=view_direction_data,
)
# Calculate shifts to apply to point
shifts = projected_position - original_position
# Update position
updated_position = original_position + shifts
# Clamp updated position to bounding box
clamped = np.where(updated_position > 1, 1, updated_position)
clamped = np.where(clamped < -1, -1, clamped)
# update
point_layer.data = clamped
yield
# reenable interactivity
layer.interactive = True
# setup viewer
viewer.camera.angles = (45, 30, 30)
viewer.camera.zoom = 100
viewer.text_overlay.visible = True
viewer.text_overlay.text = """'shift' + click and drag to move the pink point
normal click and drag to rotate the scene
"""
if __name__ == '__main__':
napari.run()