Get a point on object under the cursor

Hello.

I’m just starting programming and don’t have too much experience.

I’m trying to place a section interactively using cursor’s location.

However, in neither of its modes does rhinoscriptsyntax.GetCursorPos() return a point the cursor is placed on, unless the view is constrained to a certain CPlane. The expected behaviour is portrayed in the first image below, where the coordinates of a cursor correspond to such of a placed point.

Could anyone please tell me, can this be implemented in Python?

The second image shows the section’s result, as well as the position of the cursor.

I think you can use Getpoint, then BrepClosestPoint to give you the location on the object to draw the section. Does that work in your case?

You ask Claude how to do this, it can whip up some sample code.

I don’t think you can use GetPoint it’s limited to the current cplane/snapping behaviour i think, so it just finds the point on your cplane, then tries to find the closest thing ISH. It doesn’t shoot out a ray from the viewpoint or have any understanding of depth.

Maybe it’s over engineered but in my plugin, there’s a zbuffer capture (so how far away things are) and it reads the ZValueAt from the cursor coordinates, then it can call WorldPointAt(x, y)

Now in my code it’s spread out and in F# [Link 1](RhinosCanFly/src/Platform/Win/MouseOverrides/GestureNavigationTransitions.fs at 17b3b8da0306f2603e1fe99e3894534dd1f96a91 · Viterkim/RhinosCanFly · GitHub) and F# [Link 2]( RhinosCanFly/src/Fly/ViewTarget.fs at 17b3b8da0306f2603e1fe99e3894534dd1f96a91 · Viterkim/RhinosCanFly · GitHub)

BUT… this is probably a minimum version in python (from gippity, cut down, seems to work).

import Rhino
import scriptcontext as sc
from System.Drawing import Point

view = sc.doc.Views.ActiveView
viewport = view.ActiveViewport

screen = Rhino.UI.MouseCursor.Location
client = viewport.ScreenToClient(Point(int(screen.X), int(screen.Y)))

capture = Rhino.Display.ZBufferCapture(viewport)

try:
    depth = capture.ZValueAt(client.X, client.Y)

    if 0.0 < depth < 1.0:
        point = capture.WorldPointAt(client.X, client.Y)
        sc.doc.Objects.AddPoint(point)
        sc.doc.Views.Redraw()
        print(point)
    else:
        print("Nothing under cursor")
finally:
    capture.Dispose()

(I don’t know why it doesn’t show the ‘reply’ ribbon above my post, but this is a response to Viktor)

Thank you so much for a detailed response and an elegant solution.

In meantime, I was able to get the desired result via GetPoint Constrained to a mesh while overriding GetPoint class to hook up to OnDynamicDraw and get e.CurrentPoint.Y from it (since I need sliding the plane on exactly one axis.

What’s funny, I actually checked your plugin out for mouse wheel controls (because that’s the next functionality I wanted to provide) and wondered if I could reach out and ask for a suggestion on how to implement these for my case :sweat_smile: .

What I have come up with was a mouse-scroll-controlled slider through Eto.Forms, but it constantly loses focus due to how OnDynamicDraw works, so I’d gotten stuck again.

Thank you. Yes, GetPoint worked in my case.

I try to not use AI for learning, mainly resorting to it to search for human-made solutions and explanations in cases where the API is unclear or lacks examples.

Hmm i don’t think you can easily use the mousewheel, rhinoscanfly uses the raw mouse from windows and takes solo ownership over it in its own thread until it passes it back, theres a whole cleanup/lease/recovery stuff between using it and not using it so rhino still gets the mouse back at the end.

Rhino has that ‘Rhino.UI.MouseCallback’ which gave me issues… but thats unrelated haha… other than that theres no OnMouseWheel or Mouse 4/5 etc, so you cant use the mousewheel.

What about using stuff like

GetPoint.Constrain(Line)
Constrain(Point3d, Point3d)

then your mouse position on a line is a ‘fake slider’ ish.

But also if you do decide to do some raw input stuff, never EVER use ‘Rhino.UI.MouseCallback’ to own and cancel mouse up/down.

I did this earlier and it caused random white screen stuff in Rhino, which only fixed itself after right clicking on the command bar.

It will literally freeze the ui, i think there’s a bug in Rhino itself and some race condition with the main thread.

Constraining the plane to a line is a great idea, and would have been a better solution if not for the current issue with secondary controls (I need to also rotate my section plane).

Since mouse wheel input is ‘prohibited’ I tried sicking to keyboard inputs, what only resulted in a headache. Since for some reason Rhino keeps reading the keys when they are no longer pressed, sometimes resulting in a crash (code for the keyboard handler has been taken from here).

Regardless, if OnDynamicDraw is used, it seems that it allows no additional external control. I thought of a second-step correction, e.g. when the plane is placed it gets passed to another OnDynamicDraw that cares only for the angle of rotation (that can be changed using your idea of constraining the point to lines).

…but due to the shape of the geometry I have to work with, this approach might not prove useful, since the plane could require realignment after the angle has been chosen. I, unfortunately, can not publicly share the code I have now, but I can send you a private message, should you be interested.

Currently I’m testing an approach through Eto forms, its sliders and their (hell yeah!) mouse wheel controls. Though I don’t know if Eto has ways to update the active document in real time yet.