jupyter-widgets / pythreejs

A Jupyter - Three.js bridge
https://pythreejs.readthedocs.io
Other
934 stars 185 forks source link

Extend Picker to pick individual Points objects. #379

Closed matthewturk closed 1 year ago

matthewturk commented 2 years ago

This adds on parameters to the Picker object so that the pick-threshold for points and lines can be adjusted, and so that it will return the instanceId of an instanced mesh as well as the index when picking on a Points object. This enables the Picker object to work with Points and PointClouds, where it returns the index into a BufferGeometry corresponding to the picked (sub)instance.

I believe this is relevant to #333, as it should enable indexing into a BufferGeometry and the corresponding attributes to retrieve the color (or other attributes of the source array).

matthewturk commented 2 years ago

Sadly, I did find it in the source and not the docs.

vidartf commented 1 year ago

Thanks! :)

anadodik commented 1 year ago

Hi, thanks for this amazing library!

I've been trying to get a Picker to work with a Points object and haven't been able to get it to work. Would it be possible to give an example of how this is supposed to work?

matthewturk commented 1 year ago

@anadodik Hi! Sorry for not replying sooner. Here's how I have used it in my library; here, pc.particle_view is of type pythreejs.objects.Points_autogen.Points (i.e., Points) and dsv.components[0].renderer is a standard Renderer object.

picker = pythreejs.Picker(controlling = pc.particle_view, all=True, event='mousemove', pointThreshold = 0.01)
ren = dsv.components[0].renderer
ren.controls = ren.controls + [picker]

hover_point = pythreejs.Mesh(geometry=pythreejs.SphereGeometry(radius=0.05),
                   material=pythreejs.MeshLambertMaterial(color='hotpink'))
ren.scene.add(hover_point)
ipywidgets.jslink((hover_point, 'position'), (picker, 'point'))

Now, whenever my mouse is within a threshold distance of a point, that point is highlighted with a pink, translucent sphere. You can also watch the index property of the picker, like:

picker.observe(update_label, "index")

For instance, my update_label function might look like:

def update_label(change):
    ind = change['new']
    if ind is not None:
        labels[0].value = f"Picked index {ind} corresponds to {pos[ind,:]} with point set to {picker.point}"

I hope that helps!