GHPython - interpolate frames - what's faster?

I’ve been working on a relatively large GH definition that will iterate through a list of frames for an animation. As an input I have list of frames and a float to smoothly interpolate through them, with one output frame, which will be used to orient geometry with.

For the purpose of an animation, the interpolation is essential: A slider will be animated from, let’s say, frame 1500 to frame 2500, with 5000 steps. The slider will then, for example, be at step 1750.2, which is why I need to interpolate.

The easiest way to do that, as far as my limited knowledge goes, is to make a quick Python plane interpolation script:

Plane1 = Planes[CurrentFullFrame]
Plane2 = Planes[CurrentFullFrame+1]

NewCenter = Plane1.Origin + (CurrentIncrement * (Plane2.Origin - Plane1.Origin))
NewXAxis = Plane1.XAxis + (CurrentIncrement * (Plane2.XAxis - Plane1.XAxis))
NewYAxis = Plane1.YAxis + (CurrentIncrement * (Plane2.YAxis - Plane1.YAxis))

CurrentFrame = rs.PlaneFromFrame(NewCenter, NewXAxis, NewYAxis)

with CurrentIncrement being 0.2 in this example, and CurrentFullFrame at 1750.

Now, there is no iteration, no loop, it’s just accessing these two planes. However, I have a lot of branches and therefore A LOT of planes. With around 2000 planes and 99 branches I’m very quickly at 200k planes, and this script is now starting to be the slowest part in my definition (it takes 2 seconds). I’m now wondering if there is a faster solution - mathematically, or maybe a different programming language? It shouldn’t take that long because it shouldn’t access all the planes, but somehow it does become slower the more planes I add to the list.

Hello,

If I understand correctly you have all your planes in a Python list and it is slow to access the 2 you need. This may simply be the access time for Python to look through the list from the start and find the planes you need.

You could put them in a dictionary instead like this:

plane_dict = {i: plane for i, plane in enumerate(Planes)}

For animation this kind of interpolation will be choppy and will be subject to gimbal lock when P1 and P2 X or Y axes point at eachother (you will get harsh sudden flipping at the halfway interpolation, try it out). Animation should use stuff like Quaternion Slerp. In Pufferfish the Tween Plane components use this (like Tween Through Planes) by having the Q (Quaternion) input true. You can see if that is faster for you and smoother animations in general. If so, you can check Rhinocommon’s Quaternion class and this thread response by Daniel Piker which has some good Quaternion info (specifically the QuaternionSpline.gh examples which are even better for animation smoothness).

If the planes being interpolated between are very close in orientation though (which I’m guessing they are if he has thousands of them), there’s probably no issue with doing simple component-wise interpolation like this.

1 Like

True, I am thinking maybe it makes more sense to define way less planes and make a path via the quat splines for speed and probably smoothness.

Thanks for the tip, Michael. The word “tween” didn’t come to mind when I was looking for interpolations.

It’s true what Daniel says, I have a lot of frames. While I have come across the problem of the planes flipping I have pretty much none of those situations in my animation.

I have a few more functions in the script that allow me to stick with the last plane if the index is larger than the list length, handle nulls, etc, so it’s difficult to take ready-made components. I will see if the Pufferfish Tween Plane component is faster in any case!

1 Like

In that case what @Dancergraham suggests about a dictionary will probably speed your search up, if the Pufferfish one is any faster it would because it evaluates them all as one list or because C# may search faster. The advantage of the Quaternion route would be when defining much less planes and interpolating all the planes between as a path, but it seems you have many specific planes you want to hit.

1 Like

Hi,

In my experience, using rhinocommon instead of the scriptsyntax can often times be somewhat beneficial in terms of performance too. All you would have to change is this:

import Rhino.Geometry as rg

# your other code

CurrentFrame = rg.Plane(NewCenter, NewXAxis, NewYAxis) 

I don’t know whether you did so, but setting the type hints (e.g. plane and integer) of the component inputs also helps.

That said, for big improvements you would need bigger changes. Dictionary searching, as described by @Dancergraham, should already bring some advantages. I don’t know about the quanterion stuff, but it looks promising.

To me this doesn’t look like it would be that hard to do with just vanilla components?
You could also simply just input trees of Plane1s and Plane2s and do merely the vector operations in Python. You could get rid of the list/dictionary searching entirely like so.

Furthermore, all the other methods that you mention above, could be bottlenecks too, so it would be good to take a look at those.
You could maybe come up with some kind of generator workflow, or even animate with the GHPython component?

It’s kinda hard to say though without an example file to toy around with.

1 Like

Quaternion is just for smoother interpolation. I think with that many planes stored in native gh would be slower probably compared to an iterative approach (throw away the data when it’s done).

@Michael_Pryor :wink:

1 Like
3 Likes

It looks like the code is written to operate on a list (i.e. the Planes variable) while the input is a DataTree. This might explain the slowness (see point 1 in this old thread), though as I understand it that shouldn’t be as big of an issue anymore.

1 Like

Thanks for all the comments. Changing that “implied” loop with a datatree input operating on a list into a tree operation could certainly speed things up, too.

For now, I pre-selected the two frames between which the script is currently iterating through, with vanilla components. Sped things up by a factor of 10…

Love numberphile @diff-arch !

1 Like