How can I select a mesh vertex by a mouse click?


(Massimiliano Fantini) #1

Hi, after uploading a mesh, it is possible for the user to add a point on the mesh by picking a vertex with a mouse click? Or, otherwise, to select a mesh vertex to obtain its 3D coordinates by picking the surface of the mesh with a mouse click?


(Mathieu Huard) #2

Can you tell me more about your use case? Using the API it is possible to make the mesh clickable, but not its individual vertices if it is really a single mesh object. Depending on your workflow, you could for example add a point cloud of the mesh vertices to the scene and make each point clickable, but how useful that is really depends on what you plan to do with this vertex after it is selected.

In the meanwhile, find here a tutorial on clickable elements in the ShapeDiver viewer (for now only using the API).


(Massimiliano Fantini) #3

Hi Mathieu, I need to pick 3points on a single mesh object, or, otherwise, add 3 points on the surface of the mesh. This is because the user, after uploading a custom mesh, have to identify 3 reference points that are needed for the workflow. In particular, I need the 3D coordinates of each picked point to design a circle centered in there. I think that a point cloud of the mesh vertices will be hard to manage due to the huge amount of generated points. I think I’ll need something such as the component “select mesh vertices” of the plugin Mesh+ (http://www.grasshopper3d.com/group/mesh).


(Mathieu Huard) #5

I understand the use case. Since picking vertices of the mesh is not possible, I would recommend instead to work with draggable pointers, for example small spheres, which can be positioned on the mesh in the viewer and then have their positions sent to Grasshopper using the API.

We are currently working on making it possible to constrain draggable elements to a specific object of the scene, which will make it more convenient in this case to pick points directly on the mesh. This feature will be available in the next few weeks. In the meantime, it is always possible to drag points in the viewer and find an approximate position that is sent to Grasshopper, where it can be projected on the mesh for more accuracy.

Check out this link where I wrote a quick demo for this functionality. Only the projection of the point on the mesh is done in grasshopper. Again, with the new feature discussed above, a much simpler solution will be possible. I will post again here when the feature is ready.


(Riccardo Majewski) #6

Ciao!
This is a short c# method i’m using recently:
It cast a ray from camera to cursor location and search for intersections with the mesh.
I rearranged outputs so it give:
P - the actual 3d point
i - the index of the nearest mesh vertex
V - the 3d point of that vertex
As how this is done, it cast rays even if you click over the grasshopper canvas , so I disabled the case of a “miss”.
Give it a try.

cursor_mesh_point
cursor_mesh_point.gh (41.9 KB)

Hope it helps.

Code:

private void RunScript(Mesh mesh, bool On, bool reset, ref object P, ref object i, ref object V)
  {
    m = mesh;
    if(reset) index = -1;
    cursor_mesh_point();
    if(index != -1){ P = pt; V = v; }
    i = index;
    if(On){Component.ExpireSolution(true);} // Expiring solution to restart "RunScript"
  }

  // <Custom additional code> 
  public Rhino.Geometry.Mesh m;
  public Rhino.Geometry.Point3d pt;
  int index = -1;
  public Rhino.Geometry.Point3d v;

  public void cursor_mesh_point(){
    if(System.Windows.Forms.Control.MouseButtons.ToString() == "Left"){
      int X = System.Windows.Forms.Cursor.Position.X;
      int Y = System.Windows.Forms.Cursor.Position.Y;
      System.Drawing.Rectangle rec = RhinoDocument.Views.ActiveView.ScreenRectangle;
      int x0 = rec.Left;
      int x1 = rec.Right;
      int y0 = rec.Top;
      int y1 = rec.Bottom;
      Rhino.Geometry.Line line = new Rhino.Geometry.Line();
      if(X > x0 & X < x1 & Y > y0 & Y < y1){
        RhinoDocument.Views.ActiveView.ActiveViewport.GetFrustumLine((X - x0), (Y - y0), out line);
        Rhino.Geometry.Ray3d ray = new Rhino.Geometry.Ray3d(line.PointAt(1), -line.UnitTangent);
        double val = Rhino.Geometry.Intersect.Intersection.MeshRay(m, ray);

        if(val > 0){ // HIT
          pt = ray.PointAt(val);
          Rhino.Geometry.PointCloud pc = new Rhino.Geometry.PointCloud(m.Vertices.ToPoint3dArray());
          index = pc.ClosestPoint(pt);
          v = m.Vertices[index];
        }

        else{ //MISS
          // index = -1; // remove comment here to take in account "misses"
        }

      }
    }
  }

(Massimiliano Fantini) #7

Thank you very much Mathieu


(Massimiliano Fantini) #8

Thank you Riccardo!


(Mathieu Huard) #9

Please note that Riccardo’s solution is an elegant way to do what you want to do but only inside Rhino/Grasshopper. It will not work in ShapeDiver’s online viewer as we have no way to replicate the script which overrides Rhino’s rendering conduit.


(Bodibodileg) #10

@mathieu1 Yes, our model is denied, probably because of the scripts.
We need another solution for selecting points on mesh. Any ideas?


(Mathieu Huard) #11

At the moment, I can’t offer anything significantly better than the solution I proposed in my answer above: https://jsfiddle.net/ShapeDiver/n0678uzc/

Did you try it? Does it not work in your case?


(Massimiliano Fantini) #12

Hi Mathieu,
I’ve seen that the demo you posted (https://jsfiddle.net/ShapeDiver/n0678uzc/) has been updated: now it is possible picking three points directly on the mesh and then drag them on the mesh itself.
Can you also pass me a Grasshopper example with the input for these three points?
Thank you very much in advance.


(Mathieu Huard) #13

Here is the grasshopper file for the demo.
This is still a temporary solution until we add the feature where points can be constrained to the mesh when dragging them. For now, the projection on the mesh is done in Grasshopper.drag_and_project.gh (281.2 KB)


(Massimiliano Fantini) #14

Ok, thank you Mathieu!