15
15
class PolygonSelector (BaseSelector ):
16
16
_features = {"selection" : PolygonSelectionFeature }
17
17
_last_click = (- 10 , - 10 , 0 )
18
+ _move_mode = None
18
19
19
20
@property
20
21
def parent (self ) -> Graphic | None :
@@ -54,17 +55,20 @@ def limits(self, values: Tuple[float, float, float, float]):
54
55
55
56
def __init__ (
56
57
self ,
58
+ selection : Optional [Sequence [Tuple [float ]]],
57
59
limits : Sequence [float ],
58
60
parent : Graphic = None ,
61
+ resizable : bool = True ,
59
62
fill_color = (0 , 0 , 0.35 , 0.2 ),
60
63
edge_color = (0.8 , 0.6 , 0 ),
61
- edge_thickness : float = 8 ,
64
+ edge_thickness : float = 4 ,
62
65
vertex_color = (0.7 , 0.4 , 0 ),
63
66
vertex_size : float = 8 ,
64
67
name : str = None ,
65
68
):
66
69
self ._parent = parent
67
70
self ._move_info : MoveInfo = None
71
+ self ._resizable = bool (resizable )
68
72
69
73
BaseSelector .__init__ (self , name = name , parent = parent )
70
74
@@ -75,19 +79,30 @@ def __init__(
75
79
self .geometry .positions .draw_range = 0 , 0
76
80
self .geometry .indices .draw_range = 0 , 0
77
81
78
- edge = pygfx .Line (
82
+ self . _edge = pygfx .Line (
79
83
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
+ ),
81
87
)
82
- points = pygfx .Points (
88
+ self . _points = pygfx .Points (
83
89
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
+ ),
85
93
)
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 )
88
98
self ._set_world_object (group )
89
99
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 ))
91
106
92
107
self .edge_color = edge_color
93
108
self .edge_width = edge_thickness
@@ -233,7 +248,7 @@ def get_selected_indices(
233
248
-------
234
249
Union[np.ndarray, List[np.ndarray]]
235
250
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
237
252
| list of indices along the x-dimension for each line if graphic is a line collection
238
253
| array of indices along the x-dimension if graphic is a line
239
254
"""
@@ -296,82 +311,96 @@ def get_selected_indices(
296
311
def _fpl_add_plot_area_hook (self , plot_area ):
297
312
self ._plot_area = plot_area
298
313
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
-
304
314
# pointer move to change endpoint of segment
305
315
self ._plot_area .renderer .add_event_handler (
306
- self ._move_segment_endpoint , "pointer_move "
316
+ self ._on_pointer_down , "pointer_down "
307
317
)
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" )
310
322
311
323
self .position_z = len (self ._plot_area ) + 10
312
324
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 ()
316
327
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 ):
317
333
world_pos = self ._plot_area .map_screen_to_world (ev )
318
334
if world_pos is None :
319
335
return
320
336
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
328
347
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
331
350
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 ()
346
361
347
- def _move_segment_endpoint (self , ev ):
362
+ def _on_pointer_move (self , ev ):
348
363
"""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 :
350
365
return
351
-
352
366
world_pos = self ._plot_area .map_screen_to_world (ev )
353
367
if world_pos is None :
354
368
return
355
369
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
+
359
397
self ._selection .set_value (self , data )
360
398
361
399
def _finish_polygon (self , world_pos ):
362
400
"""finishes the polygon, disconnects events"""
363
-
364
401
self .world_object .children [0 ].material .loop = True
365
-
366
402
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
375
404
376
405
377
406
def is_left (p0 , p1 , p2 ):
0 commit comments