Mouse-over point OR the Object - why not both?


SMOVE

First of all, thank you all for your advice and code snippets, it really helps. This is an amazing group which is really inspiring!

Here’s my current premature version of SMove (a SmartMove alternative to the std Move command), which aims to demonstrate how the intended SMove command really should work. It needs more functionality as described in the header, but the basic idea is covered here.

CONTRIBUTE
Anyone with the self confidence is free to contribute (of course), but don’t forget to make a notice about new version and your signature. Then test it and upload to share. I will continue to work on it when I have code solutions for the feature list as described. Short version of SMove purpose:

SUMMARY

  1. Only one click to select Start point
  2. Mouse-over highlighting to indicate which object is hovered over.
  3. Osnap point highlighting indicating where on the focused object the snap will land.
  4. TAB-bing to toggle among available OSnap points (End, Mid, End, and back again etc)
  5. All this makes for a Faster, more Accurate, and it follows, Less Tiring command (due to less need for deep concentration).
  6. This model for selection in a command is applicable in many other commands as well, like Copy, Mirror, etc.

I would appreciate advice about how to configure the script so be available like any std Rhino command which can be repeated etc.

// Rolf


FYC: The main loop starts at the line “# START POINT” far below

import Rhino
import System.Drawing.Color
import scriptcontext as ctx
import rhinoscriptsyntax as rs

# ------------------------------------------------------------------
# SMove - A customized Smart-Move command that picks a default start 
# point without extra clicks
# ------------------------------------------------------------------
# MORE INFO
# The SMove command must highlight the Mouse-over object AND the OSnap 
# point for the start point. Only one click to select the first object and 
# its position. The picked object(s) are added to selection. TAB should alter the 
# first picked OSnap point. A Line, for example, should toggle between either 
# End points through the Mid point. 
# A Solid should do likewise, but along its edges. CTRL-TAB could alter, 
# not the OSnap point, but the edge itself.
# -------------------------------------------------------------------
# Rev 0.1.0     - 2017-02-20 RIL
# Rev 0.?.?     - 2017-??-?? Signature
# Rev 0.?.?     - 2017-??-?? Signature
# Rev 0.?.?     - 2017-??-?? Signature
# 
# TODO:
# [ ] Restrict first pick point from selecting nearby objects when no object was 
#     actually hit (intersecting with a sphere as suggested by @clement is probably a good idea).
# [ ] Enable multiple objects to be picked (While loop while pressing SHIFT?), 
#     The first pick (if any) determine the starting point. 
#     If window-selected from start, then automagically revert to "old" 
#     standard Move command (for explicitly picking the start point).
# [ ] Allow select & Move of multi selection (as of 0.1.0 only one object 
#     can be moved)
# [ ] TAB-toggle OSnap point of selected (first) Start point (see MORE INFO).
# [ ] CTRL-TAB-toggle OSnap point to edge for solids.
# [ ] (Something similar to TAB-select for selecting surfaces of a solid?)
# [ ] Set first selected object in focus in Object Proterty Panel (or, output 
#     object name to status bar, or command line as info-tect? Other?)
# [ ] Add a rev-notice above for each addition.
#
# -------------------------------------------------------------------


def SMove():
    # PRE SET
    line_color = System.Drawing.Color.FromArgb(200,0,0) # Dynamic line color 
    startObj = None
    endObj  = None

    # DynamicDraw (dyn line from start pt to current mouse position)
    def GetPointDynamicDrawFunc( sender, args ):
        args.Display.DrawLine(start_pt, args.CurrentPoint, line_color, 2)
        args.Display.DrawLine(end_pt, args.CurrentPoint, line_color, 2)
        # DynamicDraw event

    #PICK START
    def PickStartPoint(msg, obj):
        res = False
        pt = None
        obj = None
        rc, pt = Rhino.Input.RhinoGet.GetPoint(msg, False)
        if( rc!=Rhino.Commands.Result.Success ):
            return
        # Get first object, and allow for changing start point:
        arrAll = rs.NormalObjects()
        if arrAll:
            arrClosest = rs.PointClosestObject(pt, arrAll) 
            if arrClosest:                
                obj = arrClosest[0] #obj = arrClosest[len(arrClosest)-1]
                if not obj: 
                    return
                elif rs.IsObject(obj):
                    rs.SelectObject(obj)
        if not obj:
            return res, pt, obj
        return True, pt, obj
        # PickObject()

    #PICK END
    def PickEndPoint(msg, obj):
        pt = None
        # Enable dynamic draw of line from start to mouse, an instance of a 
        # GetPoint class added as a delegate for the DynamicDraw event (also
        # later used as the End point):
        cpt = Rhino.Input.Custom.GetPoint()
        cpt.SetCommandPrompt(msg)
        cpt.DynamicDraw += GetPointDynamicDrawFunc
        cpt.Get()        
        # Object to point
        pt = cpt.Point()
        # No SelectObject for end point
        return True, pt, cpt

    # START POINT
    res, start_pt, startObj = PickStartPoint("Start point", startObj)
    if not res: 
        return

    # END POINT
    res, end_pt, cpt = PickEndPoint("End point", endObj)
    if not res: 
        return

    # MOVE
    if(cpt.CommandResult() == Rhino.Commands.Result.Success): #and (endObj):
        rs.MoveObject(startObj, end_pt-start_pt)
        ctx.doc.Views.Redraw()
        
if( __name__ == "__main__" ):
    SMove()