Pause script to allow user to position objects before continuing?

Hi, I’m working on a script that needs to allow the user to select and drag an object to a new location before continuing. I know how to pause a script to wait for user input (string) or selection of objects, but is there any way to wait for the user to select/reposition an object, then hit enter before continuing? Thanks.

hi @btub,

I don’t know how to have a ‘drag’ mode (standard Rhino dragging) inside of your script. But perhaps you can use a workaround - see attached script for one possibility.

hth,

Jarek

drag.rvb (637 Bytes)

Thanks, @Jarek - I’ll need to convert this to Python so will let you know if it works.

Hi @Jarek,

I ported your script to Python and unfortunately the Do loop (“while True:” in Python) just hangs Rhino, probably because it’s trying to constantly redraw? Is there really no way to pause a script to wait for a user to select/move an object, then hit enter before continuing?

def main():
    idObject = rs.GetObject("Select object to drag")
    if idObject is None: return
    rs.Prompt("Drag object (Enter/RMB when done)")
    while True:
        arrP = bBoxCenter(rs.BoundingBox(idObject))
        strPoint = "{0[0]:.3f}, {0[1]:.3f}, {0[2]:.3f}".format(arrP)
        rs.MoveObject(idObject, strPoint)
        if rs.LastCommandResult() != 0:
            break

     return

def bBoxCenter(arrBBox):
    BboxCenter = rs.PointAdd(arrBBox[0], rs.VectorScale(rs.VectorCreate(arrBBox[6], arrBBox[0]), 0.5))
    return BboxCenter

if __name__ == "__main__":
    main()

Also, Rhino Python does not have a way to call Pt2Str(), so I followed an example from another thread that attempts to recreate it.

Hi @btub,

I didn’t ‘convert’ to Python yet, so can’t tell for sure, but I think the problem with your converted script is that you use rs.MoveObject method rather than rs.Command("_Move…") - see rvb file - this way inside your script you actually stop to run the regualr Rhino ‘Move’ command, automatically use bounding box of your object as ‘from’ point, and it loops until the command was canceled/unsuccessful (in that case LastCommandResult<>0.

Try replacing the rs.Move method with rs.Command("_Move…)

Unless you are running Rhino on Mac, you can run the rvb file and see how it behaves.

~j

When I replace rs.MoveObject with rs.Command("_Move…"):

rs.Command("_Move " + str(strPoint) + " _Pause _EnterEnd", False)

I get a bunch of “unknown command” errors in the History window (i.e., each of the coordinates).

Unknown command: -2.500,
Unknown command: 25.000,
Unknown command: 0.000

So it doesn’t seem like _Move is accepting the proper parameters? Yes, I am running Rhino on Mac.

Ok, I have no way of testing it on Mac.

What happens if you just run:

  rs.Command("_Move -2.5,25,0 _Pause _EnterEnd, False)")

Works here on PC… make sure your strPoint is formatted to look like x,y,z – no spaces or other extra characters.

No luck. Seeing a similar error in the history window:

Unknown command: -2.5,25,0

I know that command line works a bit different on Mac than PC. So maybe the command combo should look different too. But I have no way of testing it, sorry! If you can get this part to work, the ‘workaround’ should be OK for dragging. Maybe you can check with Rhino for Mac forum category…

~j

Ok, I think I have something that works! It prompts you to select an object to move, then will place the object when you click the left mouse button. It will then continue asking you to select other objects to move until you hit the enter/return key. Note that I’m using this on Rhino for Mac. Thanks for your help!

def main():
    while True:
        idObject = rs.GetObject("Select object to drag (Enter when done)", 0, False, True, None, True)
        if idObject is None: break

        arrP = bBoxCenter(rs.BoundingBox(idObject))
        rs.Command("_Move " + str(arrP) + " _Pause _EnterEnd", False)
        if rs.LastCommandResult() != 0:
            break

    return

def bBoxCenter(arrBBox):
    BboxCenter = rs.PointAdd(arrBBox[0], rs.VectorScale(rs.VectorCreate(arrBBox[6], arrBBox[0]), 0.5))
    return BboxCenter

if __name__ == "__main__":
    main()

Great-- in my rvb workaround suggestion, the getObject was outside the loop so once you select it, you can keep moving the same object until canceling the command, similar way to dragging. But should work either way, depends what you need in your main script.

~j

Actually, I’m still running into one annoying issue. When I first click on the object to move, it automatically re-centers on the point I clicked on. However, looking at the code, it should simply re-center to it’s original bounding box (i.e., shouldn’t move) until the user moves/drags the object?

In the photo above, the object’s original location is in gray, and it has re-centered on the point that I clicked on the object (lower right point).

Hi @btub,

In the original script the bounding box center was used since the objects was only selected once, and then constantly being moved (dragged) without selecting each time, so bbox center was being used as the ‘from’ point for move.

In the current scheme (need to click the object for each move) this is unnecessary and causes ‘jumping’ once you click to the center.

Try it this way (below). It uses GetObjectEx method that not only returns selected object [0] but also the selection point [3] that is later on used as the move ‘from’ point:

import rhinoscriptsyntax as rs

def main():
    while True:
        arrObject = rs.GetObjectEx("Select object to drag (Enter when done)",0,False,True)
        if arrObject is None: break
        idObject = arrObject[0]
        arrP = arrObject[3]
        rs.Command("_Move " + str(arrP) + " _Pause _EnterEnd", False)
        if rs.LastCommandResult() != 0:
            break
    return

if __name__ == "__main__":
    main()

@Jarek Yes, that works. Thanks!

Hello,
Just looking at your code:
some proposal.
As the break use is not the best solution and you choosed the while loop.
I propose to really use it as recursive function.

Here my idea:

import rhinoscriptsyntax as rs

def main():

if rs.LastCommandResult() != 0:
    return
while rs.LastCommandResult()== False:
    arrObject = rs.GetObjectEx("Select object to drag (Enter when done)",0,False,True)
    idObject = arrObject[0]
    arrP = arrObject[3]
    rs.Command("_Move " + str(arrP) + " _Pause _EnterEnd", False)
    
return

if name == “main”:
main()

1 Like

I was wondering if anyone has made a version of this idea that allows users to continue making changes to the scene until satisfied, and then resume an automated process—so probably implemented as as multiple scripts that produce and consume some intermediary file to hold data in the interim?

The problem as I see it is that there may need to be multiple transforms applied to get the scene ready to continue with automated tasks.

Thoughts?

One way I can think of is using the GetString method with some options (including ‘DONE’ for example) and if the resulting string is different than the GetString options, passing the result to Rhino.Command() method so regular Rhino commands can be used within the script, then, once user picks ‘DONE’, you can proceed with the rest of the code.

Do
   strResult=Rhino.GetString("Options",,array("DONE"))
   if strResult="DONE" then
      Exit Do
   Else
      Call Rhino.Command(strResult)   
   End If
Loop

That is an excellent suggestion :blush: why didn’t I think of it? I’m off to try it, thanks!