Skip to content

Commit 79c4952

Browse files
committed
wip interaction
1 parent d3bab84 commit 79c4952

File tree

5 files changed

+94
-77
lines changed

5 files changed

+94
-77
lines changed

fastplotlib/graphics/image.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -460,19 +460,13 @@ def add_polygon_selector(
460460
initial points for the polygon
461461
462462
"""
463-
# default selection is 25% of the diagonal
464-
if selection is None:
465-
diagonal = math.sqrt(
466-
self._data.value.shape[0] ** 2 + self._data.value.shape[1] ** 2
467-
)
468-
469-
selection = (0, int(diagonal / 4), 0, int(diagonal / 4))
470463

471464
# min/max limits are image shape
472465
# rows are ys, columns are xs
473466
limits = (0, self._data.value.shape[1], 0, self._data.value.shape[0])
474467

475468
selector = PolygonSelector(
469+
selection,
476470
limits,
477471
fill_color=fill_color,
478472
parent=self,

fastplotlib/graphics/line.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,11 @@ def add_polygon_selector(
319319
ymin = np.floor(y_axis_vals.min()).astype(int)
320320
ymax = np.ceil(y_axis_vals.max()).astype(int)
321321

322-
# default selection is 25% of the image
323-
if selection is None:
324-
selection = []
325-
326322
# min/max limits
327323
limits = (x_axis_vals[0], x_axis_vals[-1], ymin * 1.5, ymax * 1.5)
328324

329325
selector = PolygonSelector(
326+
selection,
330327
limits,
331328
parent=self,
332329
**kwargs,

fastplotlib/graphics/line_collection.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ def add_linear_region_selector(
452452

453453
def add_rectangle_selector(
454454
self,
455-
selection: tuple[float, float, float, float] = None,
455+
selection: tuple[float, float, float] = None,
456456
**kwargs,
457457
) -> RectangleSelector:
458458
"""
@@ -515,15 +515,10 @@ def add_polygon_selector(
515515

516516
ymax = np.ptp(bbox[:, 1])
517517

518-
if selection is None:
519-
selection = []
520-
521518
limits = (xmin, xmax, ymin - (ymax * 1.5 - ymax), ymax * 1.5)
522519

523-
if selection is not None:
524-
selection = [] # TODO: fill selection
525-
526520
selector = PolygonSelector(
521+
selection,
527522
limits,
528523
parent=self,
529524
**kwargs,

fastplotlib/graphics/selectors/_base_selector.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class MoveInfo:
2828
# WorldObject or "key" event
2929
source: WorldObject | str
3030

31+
ref: Any = None
32+
3133

3234
# key bindings used to move the selector
3335
key_bind_direction = {

fastplotlib/graphics/selectors/_polygon.py

Lines changed: 88 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
class PolygonSelector(BaseSelector):
1616
_features = {"selection": PolygonSelectionFeature}
1717
_last_click = (-10, -10, 0)
18+
_move_mode = None
1819

1920
@property
2021
def parent(self) -> Graphic | None:
@@ -54,17 +55,20 @@ def limits(self, values: Tuple[float, float, float, float]):
5455

5556
def __init__(
5657
self,
58+
selection: Optional[Sequence[Tuple[float]]],
5759
limits: Sequence[float],
5860
parent: Graphic = None,
61+
resizable: bool = True,
5962
fill_color=(0, 0, 0.35, 0.2),
6063
edge_color=(0.8, 0.6, 0),
61-
edge_thickness: float = 8,
64+
edge_thickness: float = 4,
6265
vertex_color=(0.7, 0.4, 0),
6366
vertex_size: float = 8,
6467
name: str = None,
6568
):
6669
self._parent = parent
6770
self._move_info: MoveInfo = None
71+
self._resizable = bool(resizable)
6872

6973
BaseSelector.__init__(self, name=name, parent=parent)
7074

@@ -75,19 +79,30 @@ def __init__(
7579
self.geometry.positions.draw_range = 0, 0
7680
self.geometry.indices.draw_range = 0, 0
7781

78-
edge = pygfx.Line(
82+
self._edge = pygfx.Line(
7983
self.geometry,
80-
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
84+
pygfx.LineMaterial(
85+
thickness=edge_thickness, color=edge_color, pick_write=False
86+
),
8187
)
82-
points = pygfx.Points(
88+
self._points = pygfx.Points(
8389
self.geometry,
84-
pygfx.PointsMaterial(size=vertex_size, color=vertex_color),
90+
pygfx.PointsMaterial(
91+
size=vertex_size, color=vertex_color, pick_write=False
92+
),
8593
)
86-
mesh = pygfx.Mesh(self.geometry, pygfx.MeshBasicMaterial(color=fill_color))
87-
group = pygfx.Group().add(edge, points, mesh)
94+
self._mesh = pygfx.Mesh(
95+
self.geometry, pygfx.MeshBasicMaterial(color=fill_color, pick_write=False)
96+
)
97+
group = pygfx.Group().add(self._edge, self._points, self._mesh)
8898
self._set_world_object(group)
8999

90-
self._selection = PolygonSelectionFeature([], [0, 0, 0, 0])
100+
# if selection is None:
101+
if selection is None:
102+
self._move_mode = "create" # picked up by _fpl_add_plot_area_hook in a sec
103+
selection = [(0, 0, 0)]
104+
self.geometry.positions.draw_range = 0, 1
105+
self._selection = PolygonSelectionFeature(selection, (0, 0, 0, 0))
91106

92107
self.edge_color = edge_color
93108
self.edge_width = edge_thickness
@@ -233,7 +248,7 @@ def get_selected_indices(
233248
-------
234249
Union[np.ndarray, List[np.ndarray]]
235250
data indicies of the selection
236-
| tuple of [row_indices, col_indices] if the graphic is an image
251+
| array of (x, y) indices if the graphic is an image
237252
| list of indices along the x-dimension for each line if graphic is a line collection
238253
| array of indices along the x-dimension if graphic is a line
239254
"""
@@ -296,82 +311,96 @@ def get_selected_indices(
296311
def _fpl_add_plot_area_hook(self, plot_area):
297312
self._plot_area = plot_area
298313

299-
self._plot_area.controller.enabled = False
300-
301-
# click to add new segment
302-
self._plot_area.renderer.add_event_handler(self._on_click, "click")
303-
304314
# pointer move to change endpoint of segment
305315
self._plot_area.renderer.add_event_handler(
306-
self._move_segment_endpoint, "pointer_move"
316+
self._on_pointer_down, "pointer_down"
307317
)
308-
309-
self.__.add_event_handler(pfunc_down, "pointer_down")
318+
self._plot_area.renderer.add_event_handler(
319+
self._on_pointer_move, "pointer_move"
320+
)
321+
self._plot_area.renderer.add_event_handler(self._on_pointer_up, "pointer_up")
310322

311323
self.position_z = len(self._plot_area) + 10
312324

313-
def _on_click(self, ev):
314-
last_click = self._last_click
315-
self._last_click = ev.x, ev.y, ev.time_stamp
325+
if self._move_mode == "create":
326+
self._start_move_mode_create()
316327

328+
def _start_move_mode_create(self):
329+
self._plot_area.controller.enabled = False
330+
self._move_mode = "create"
331+
332+
def _on_pointer_down(self, ev):
317333
world_pos = self._plot_area.map_screen_to_world(ev)
318334
if world_pos is None:
319335
return
320336

321-
if np.linalg.norm([last_click[0] - ev.x, last_click[1] - ev.y]) > 5:
322-
self._start_finish_segment(world_pos)
323-
elif (ev.time_stamp - last_click[2]) < 2:
324-
self._last_click = (-10, -10, 0)
325-
self._finish_polygon(world_pos)
326-
else:
327-
pass # a too slow double click
337+
if self._move_mode == "create":
338+
last_click = self._last_click
339+
self._last_click = ev.x, ev.y, ev.time_stamp
340+
if np.linalg.norm([last_click[0] - ev.x, last_click[1] - ev.y]) > 5:
341+
self._add_polygon_vertex(world_pos)
342+
elif (ev.time_stamp - last_click[2]) < 2:
343+
self._last_click = (-10, -10, 0)
344+
self._finish_polygon(world_pos)
345+
else:
346+
pass # a too slow double click
328347

329-
def _start_finish_segment(self, world_pos):
330-
"""After click event, adds a new line segment"""
348+
elif self._move_mode is None:
349+
# No move mode, so we can initiate a drag if we clicked on a vertex
331350

332-
self._move_info = MoveInfo(
333-
start_selection=None,
334-
start_position=world_pos,
335-
delta=np.zeros_like(world_pos),
336-
source=None,
337-
)
338-
339-
# line with same position for start and end until mouse moves
340-
if len(self.selection) == 0:
341-
data = np.vstack([self.selection, world_pos, world_pos])
342-
else:
343-
data = np.vstack([self.selection, world_pos])
344-
345-
self._selection.set_value(self, data)
351+
self._move_mode = "drag"
352+
self._move_info = MoveInfo(
353+
start_selection=self.selection,
354+
start_position=world_pos,
355+
delta=np.zeros_like(world_pos),
356+
source=None,
357+
)
358+
# TODO: initite drag, eirher on an existing vertex, or a new one
359+
# TODO: also delete vertices by double clicking them?
360+
breakpoint()
346361

347-
def _move_segment_endpoint(self, ev):
362+
def _on_pointer_move(self, ev):
348363
"""After mouse pointer move event, moves endpoint of current line segment"""
349-
if self._move_info is None:
364+
if self._move_mode is None:
350365
return
351-
352366
world_pos = self._plot_area.map_screen_to_world(ev)
353367
if world_pos is None:
354368
return
355369

356-
# change endpoint
357-
data = self.selection
358-
data[-1] = world_pos
370+
if self._move_mode == "create":
371+
# change endpoint
372+
data = self.selection
373+
data[-1] = world_pos
374+
self._selection.set_value(self, data)
375+
376+
def _on_pointer_up(self, ev):
377+
if self._move_mode == "drag":
378+
self._move_mode = None
379+
self._move_info = None
380+
381+
def _add_polygon_vertex(self, world_pos):
382+
"""After click event, adds a new line segment"""
383+
384+
# self._move_info = MoveInfo(
385+
# start_selection=None,
386+
# start_position=world_pos,
387+
# delta=np.zeros_like(world_pos),
388+
# source=None,
389+
# )
390+
print(world_pos)
391+
# line with same position for start and end until mouse moves
392+
if len(self.selection) == 0:
393+
data = np.vstack([self.selection, world_pos, world_pos])
394+
else:
395+
data = np.vstack([self.selection, world_pos])
396+
359397
self._selection.set_value(self, data)
360398

361399
def _finish_polygon(self, world_pos):
362400
"""finishes the polygon, disconnects events"""
363-
364401
self.world_object.children[0].material.loop = True
365-
366402
self._plot_area.controller.enabled = True
367-
368-
handlers = {
369-
self._on_click: "click",
370-
self._move_segment_endpoint: "pointer_move",
371-
}
372-
373-
for handler, event in handlers.items():
374-
self._plot_area.renderer.remove_event_handler(handler, event)
403+
self._move_mode = None
375404

376405

377406
def is_left(p0, p1, p2):

0 commit comments

Comments
 (0)