Curve frames (once again)

I know there are many threads around curve frames and I have looked at a ton of them, but could not find a satisfactory solution.

Basically I am trying to find a way to get curve frames somewhat reliably.

The frames should be:

  1. the x-axis should always align with the curve tangent
  2. the z and y axis should not suddenly change direction when the curvature flips from one side to the other

It has to work on any open or closed nurbs curve.

You would think it is fairly straight forward since we as humans have a intuitive sense of how the frames should align along any curve. If we think of a roller coaster, that is a good example of where the 2 principles absolutely have to match. Of course with a roller coaster a third principle comes into play with “leaning” into the curve so that the acceleration vector is always pointing down. This would be a nice bonus. A roller coaster might have some intentional extra twists, lets ignore those.

Well, seems like it is not so easy to actually do.

I have seen many mentions of the Frenet-Serret formula and suggestions to “just use that”. So my first question would be: Is this algorithm used in any of the curve frame components?

Playing around I have found that there are 2 difficult cases: changing curvature and circles placed directly on the X, Y or Z base planes.

Looking at the normal Curve Frame component (Method 1) it has the problem that the z-axis tends to flip where the curvature goes from one side to another side of the curve.

Now trying to fix that with flipping certain planes using dot products (Method 2) works, but usually only in one plane.

I have devised a third method, which seems to be a lot closer to what I am after, but fails with the circle in YZ plane. Here everything is more or less oriented to have Z up, similar to the roller coaster example.

Maybe there is no solution that has satisfactory results in all cases. But maybe there is, and I would like to/need to find it.

So far in all my many years of using Grasshopper this is the one problem that riddles me over and over again.

evaluate_curve.gh (64.9 KB)

I don’t exactly know how the curve frames are oriented, but it seems that Y gets aligned to either world X, Y or Z. How the axis is chosen is a mystery.

I tried a surfacic approach by sweeping a horizontal line along the curve to give a base surface, which by definition has a local normal vector. It seems the orientation of the kettles is consistent.

I’m more used to work with Perp Frames rather than Curve Frames but I think you can fill in the gaps from here.

evaluate_curve.gh (67.2 KB)

1 Like

That is an awesome technique, thanks!

I have played around with your technique and decided to simplify it a bit in the later part. I am simply using evaluate surface. This will be helpful as I have to rebuild this using the Rhino3dm library in another software tool.

I am calling it “Magic Teddy’s Sweep Evaluate” technique :smiley:

evaluate_curve_sweep.gh (72.3 KB)

1 Like

One way to do it is to use anemone loop. You align the second plane to the first and the third to the second and the fourth to the third. I remember doing this three years ago but I can’t find the script. I’ll give it a try tomorrow.

Yes, I was thinking about using an iterative approach as well. But I think I would then actually try to use a physics based approach where you use forces and speed to lean into the curve like you would for designing a race track.

Curious how you did it though!

Getting the Perpendicular Frame via Python seems to be a little more stable. Maybe it could be an option.

Return a 3d frame at a parameter. This is slightly different than FrameAt in that the frame is computed in a way so there is minimal rotation from one frame to the next.

evaluate_curve_v2.gh (67.8 KB)

2 Likes

Nice. I love how simple the technique is. One thing I have noticed though is that just like evaluate curve for more complex curves the distances between frames is not consistent:

If you rebuild the curve the frames are spaced equally but then you re-introduce cases where there are sudden flips in the orientation:

But I will definitely save this as a user object since it seems superior to the normal curve frame component!

For the distance, I would use the Parameters output from Divide Distance (DivDist).

If you want to avoid any intersection, I have also done this recursively in python in the past, where you find the intersection of the first object with the curve, and use this to position the next…and so on.

I’ll think about a patent, thanks.

As for the equal spacing issue, it’s because you are trying to get the parameters directly from dividing the [0,1] domain equally. But even if you reparameterize a curve, there is no reason that the parameter should increase linearly between start and end points. It does for simple enough curves, but not complex NURBS.

If you want to have equal spacing, then use Divide Curve and use the Parameters output.
(Also, I think the Python code does exactly the same thing as Perp Frame component)

evaluate_curve_v2.gh (64.5 KB)

EDIT : exactly as @Adam_M said while I was replying :smiley:

1 Like

Thanks to both of your answers. Yes, I am aware of either having to rebuild a curve or using Divide Distance.

That’s actually why I like this sweep technique with the surface, since it appears that surfaces have equally spaced U and V coordinates regardless of shape?! At least looking at the results it appears that way.

Like mentioned I am basically using rhino3dm .NET in another application and only really have access to Evaluate Curve and Evaluate Surface from the Rhino world. Sadly DivideDistance does not seem to be part of rhino3dm.

So I think I will continue with the sweep technique since you also get a nice preview of how objects will align along the curve even before actually placing objects.