Animate Rhino Viewport with Rhino Python?

Hi everybody,

Is it possible to animate the Rhino viewport with Python in order to run, for example a simulation that you can follow in real time, instead of seeing just the outcome. I’m currently looking for a Rhino Python solution without grasshopper!

A simple example would be a moving point that is - each frame or iteration - randomly displaced, and its movement can be seen live in the Rhino viewport.

I tried this, but it didn’t really work:

import Rhino.Geometry as rg
import rhinoscriptsyntax as rs
import random
import time

run_time = 10

pt = rg.Point3d(0.0, 0.0, 0.0)

for t in range(run_time):
    vec = rg.Vector3d(random.random(), random.random(), 0.0)
    pt += vec
    pt_id = rs.AddPoint(pt)
    time.sleep(.25)
    if t < run_time - 1:
        rs.DeleteObject(pt_id)

Getting the timing right is nearly impossible and creating, then deleting objects each frame is probably not very clever either!

Any suggestions?

Update (March 25th, 2019):

Windows:

The script, kindly provided by @clement below, mostly works on Rhino v5 and v6 for Windows.

macOS:

Forced viewport animations are currently not possible in Rhino for Mac v5 (5.5.3 or lower). They seems to be working in the current v6 (WIP), though.

1 Like

I’ve done a few with Python, it’s not too hard. Yes, adding and then deleting objects is inefficient if it’s the same object, you should just move the original instead. And yes, timing will not be very predictable, depending on how long each operation takes to calculate.

One other thing you will find is that Rhino is adding all the operations you do to the undo stack, so it may start to consume large amounts of memory. There is no workaround for that as far as I know, aside from creating “virtual” geometry that is not added to the document and then displaying it via a custom display conduit (what Grasshopper does essentially).

1 Like

@diff-arch, simplest possible example for a conduit displaying a point in a list of points:


import Rhino
import scriptcontext
import rhinoscriptsyntax as rs
import System

class MyConduit(Rhino.Display.DisplayConduit):
    def __init__(self, index, points):
        self.index = index
        self.points = points
        self.color = System.Drawing.Color.Red

    def PostDrawObjects(self, e):
        e.Display.DrawPoint(self.points[self.index], self.color)

One way to use it:

def DoSomething():
    
    crv_id = rs.GetObject("Select a curve", 4, True, False)
    if not crv_id: return
    
    points = rs.DivideCurve(crv_id, 100, False, True)
    
    conduit = MyConduit(0, points)
    conduit.Enabled = True
    
    for i in xrange(len(points)):
        if scriptcontext.escape_test(False): break
        
        rs.Prompt("Frame {}".format(i))
        
        conduit.index = i
        scriptcontext.doc.Views.ActiveView.Redraw()
        
        rs.Sleep(25)
    
    conduit.Enabled = False

DoSomething()

Edit: tested on Windows, Rhino 5 and 6. May fail on mac.
_
c.

2 Likes

Thank you, @clement and @Helvetosaur for your answers.

@clement, could you kindly elaborate on a couple of things please.

I get that the MyConduit class inherits from the Rhino.DisplayConduit class and that you extend it with the custom attributes self.index, self.points and self.color.
Furthermore, you overwrite its PostDrawObjects() method, which by default does nothing. Its argument e is also passed to the original method and needs to be DrawEventArgs.
Is this method called in the background by Rhino, or why aren’t you calling it anywhere in your example?

In the DoSomething() method, you initialise an instance of the class with the points from the curve division and an index of 0, I guess to start at the first point in points? You enable the conduit and then loop over the length of the points list.
What do the following lines do?

if scriptcontext.escape_test(False): break

And:

scriptcontext.doc.Views.ActiveView.Redraw()

I couldn’t find a reference for the scriptcontext library.

I tried to run your code, but nothing really happens in my viewport. There’s just a slight pause until the script has run. The console doesn’t print any code errors either? Any ideas?

Hi @diff-arch, it is automatically called by the class when the conduit is enabled.

the first allows to cancel the animation by pressing the ESC key, the second does force a redraw of the current viewport to see the point.

I forgot to post the import section, here is the script: Conduit_AnimatePoint.py (915 Bytes)

After clicking on the curve, you should see a red point running from the start of the curve to the end of the curve. Does it work ? (I tested with Rhino 6)

scriptcontext.doc refers to Rhino.RhinoDoc which you can read about here
_
c.

2 Likes

Wow, thanks again! You’re fast. :slight_smile:

The import section wasn’t missing in my script, though. I’ve tried your script nonetheless, but the result is the same, nothing happens. I’m still using Rhino 5, since version 6 isn’t golden on macOS yet.

Do you think that, it not doing anything, is version or OS related?

@diff-arch, so your’re trying to run this on a mac ? (The script posted above runs OK in Rhino 5 and 6 on Windows, i cannot check on a mac unfortunately. Do you get the command prompt frame counter or any errors in the command line ?

_
c.

1 Like

@clement, yes, on macOS in Rhino 5.5.3. (latest version). No, all the command prompt shows is 1 curve adde to selection.

Thanks for sharing that @clement,

I would like to know where is this: e.Display.DrawPoint coming from. After since there’s no dropdown hinting I don’t know where is this coming from and what kind of other objects you can draw.

Hi @diff-arch,

we need to ask Mitch (@Helvetosaur) then. He is clever enough to own a designer laptop :wink:

1 Like

Hi @ivelin.peychev, you can find the drawing methods to add here

2 Likes

:thinking: Pipeline, who would’ve thought.

1 Like

OK, what am I supposed to test on my “designer laptop”? :thinking: It’s not completely clear… :dizzy_face:

Hi @Helvetosaur, first of all if this rhino python script, provided by clement, works. It doesn’t for me on Rhino 5.5.3. on macOS. You should see a red point moving along a curve that you provide, if asked for.

OK… (pulls out antique “designer laptop” and lets it boot)…

OK, nothing doing in 5.5.3. However it works in the current V6 WIP. So something must have been missing from V5 (not surprising, not all is implemented in Mac), but it got added in V6.

Actually, it doesn’t run in Windows V5 either…

image

2 Likes

What is so special about that laptop?

It’s a Mac. All Macs are “special”. :grin:

:rofl: Yeah I like that joke.

Thank for testing @Helvetosaur, line 5 in the layer module points to this:

from Rhino.RhinoMath import UnsetIntIndex

so the error is not caused by the script posted above but from that statement. Maybe @Alain can help?

_
c.

1 Like

@Helvetosaur, i get no error using Rhino 5.12.50810.13095, 10.08.2015 Windows.

_
c.