Hi, I am exploring the DynamicDraw function, but apparently I lack the basic knowledge.
I would like to know how I can project temporary curves on a mesh. A simple example would be:
Pick a mesh and then have a mouse over funtion that projects a circle down on the point on the mesh that the cursor hoovers above.
Illustration:
Imagine cursor arrow in middle of yellow projected circle:
below script might be used for further refinement. I´m using a circle created in the XYPlane, then move the plane to the mouse cursor which is constrained on the pre-picked mesh.
I’ve edited the script to return all intersections.
While at it I simplified the script by using the mesh-plane intersection rather than projecting a line.
I do not know however how stable that is given the state of Rhino mesh tools.
# dynamic project height curve on mesh, 2016, Jorgen Holo
# Based on "dynamic project circle on mesh, 2016, Clement Greiner - CG3D"
# Edited by willemderks to use mesh-plane intersection and add all intersections
import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
from System.Drawing import Color
def SliceMesh():
mesh_id = rs.GetObject("Select mesh", 32, True, False)
if not mesh_id: return
mesh = rs.coercemesh(mesh_id, True)
gp = Rhino.Input.Custom.GetPoint()
gp.Constrain(mesh, False)
gp.Tag = None
gp.SetCommandPrompt("Point on mesh")
def GetPointDynamicDrawFunc(sender, args):
#simplified by using mesh-plane intersection
plane = Rhino.Geometry.Plane.WorldXY
plane.Origin = args.CurrentPoint
rc = Rhino.Geometry.Intersect.Intersection.MeshPlane(mesh,plane)
rs.Prompt(str(plane.Origin.Z))
if rc.Count != 0:
for polyline in rc:
args.Display.DrawPolyline(polyline, Color.Red, 3)
#send all projected curves 'back'
sender.Tag = rc
gp.DynamicDraw += GetPointDynamicDrawFunc
getres = gp.Get()
if gp.CommandResult() != Rhino.Commands.Result.Success:
return None
if gp.Tag:
#use generater to create and return a list of new curves
crv_ids = [scriptcontext.doc.Objects.AddPolyline(polyline) for polyline in gp.Tag]
rs.SelectObjects(crv_ids)
gp.Dispose()
if __name__=="__main__":
SliceMesh()
Nice move, I was going to test with mesh mesh intersection since I saw that a clippingplane moves through complex meshes so much faster, so you just saved me a lot of time!
But do you know why the mesh-mesh intersection is so much faster than projecting a curve?
OT: Do you know why “prompt” causes lagging if I move the mouse too fast over the mesh?
A projected curve is more computational intensive because the smooth curve is projected on the mesh faces.
So the smoothness of the curve in maintained, this needs more calculations.
I don’t know why exactly but I do know that updating the commandline is time intensive. For each move of the mouse the commandline needs to be updated as well, causing lag when the mouse is moved faster than the prompt can be updated.
Yes, everything you do in a conduit slows things down. Therefore try to put as much of the code outside the GetPointDynamicDrawFunc. I doubt that drawing the 2d text in the conduit is much faster but you might try:
plane = Rhino.Geometry.Plane.WorldXY
wc = Rhino.DocObjects.CoordinateSystem.World
sc = Rhino.DocObjects.CoordinateSystem.Screen
def GetPointDynamicDrawFunc(sender, args):
# simplified by using mesh-plane intersection
plane.Origin = args.CurrentPoint
rc = Rhino.Geometry.Intersect.Intersection.MeshPlane(mesh,plane)
# draw text of height near mouse cursor
vp = args.Viewport
xform = vp.GetTransform(wc, sc)
current_pt = args.CurrentPoint
current_pt.Transform(xform)
screen_pt = Rhino.Geometry.Point2d(current_pt.X, current_pt.Y-25)
z_height = round(plane.Origin.Z, 3).ToString()
if vp.Id == scriptcontext.doc.Views.ActiveView.ActiveViewportID:
args.Display.Draw2dText(z_height, Color.White, screen_pt, True)
if rc.Count != 0:
for polyline in rc:
args.Display.DrawPolyline(polyline, Color.Red, 3)
#send all projected curves 'back'
sender.Tag = rc
This draws the z-height 25px above the mouse cursor in the active viewport only, without having to change the Cursor ToolTips settings.
btw. note that Rhino does not show any errors in the python console if they happened in a delegate (the function which does the dynamic display). I´ve reported that in the past.
Another option, to adding a custom drawing function, is to derive class from GetPoint. In doing this, it might be easier to separate your calculation code from your drawing code.
For example:
import Rhino
# Rhino.Input.Custom.GetPoint derived class
class MyGetPoint(Rhino.Input.Custom.GetPoint):
# Class initializer
def __init__(self):
# TODO: add class initialization code here
# OnMouseMove override
def OnMouseMove(self, e):
# TODO: add calculation code here,
# then call the base class so default calculations
# can be made.
Rhino.Input.Custom.GetPoint.OnMouseMove(self, e)
# OnDynamicDraw override
def OnDynamicDraw(self, e):
# TODO: add drawing code here,
# then call the base class so default drawing
# can be performed.
Rhino.Input.Custom.GetPoint.OnDynamicDraw(self, e)
gp = MyGetPoint();
gp.SetCommandPrompt('Pick a point')
gp.Get()
A bit OT, but I never messed with the ToolTips options. I tried just enabling it and definitely could be a good for people that learn Rhino to have Prompt checked…
But two things I have noticed:
When enabled with just Osnap, it show osnap a bit nicer than default osnap tooltip with disabled Tooltips (this one has a cast shadow and AA text over here)
I can’t seem to make the Background color / text color active