Flipping GH Planes forever? What is going on and how to fix it?

Many of us has struggled with them, and it just keeps haunting us - Planes which doesn’t really know which way to orient itself. But wasn’t it exactly this that Quaternions was good for, avoiding singularities and all that stuff?

LookAt Focus Point

Any way, I’m defining Quaternions based on a Plane which “LookAt” a focus point in 3D space. The direction from the `Plane.Origin` to the focal `Point` defines a vector. And based on that vector I create a new perpendicular Plane. This new Plane is then used to define a Quaternion rotation between the original Plane and the new plane in the “LookAt” direction. My quaternions, which I create in different ways for different use, are doing just fine, and so they can rotate whatever I want to rotate. Problem is , the “LookAt” plane created based on the focus point is flipping hysterically in the way GH Planes seems to prefer to do.

Q1: So my first question is - is there a systemic error in the GH Plane class? If so, are there any plans to fix it?

Q2: Is there a consistent way of defining Planes - based on direction vectors in 3d space - so that they don’t start flip like shown in the clip.

Q3: Is there an alternate way - a workaround - to define a deterministic oriented (“non-flipping”) Plane based on a direction derived from a point in 3d space as demonstrated in the clip and in my code snippet?

Fig 1. The Plane axes flips hysterically. Shown to the far right in the clip is the Quaternion scalars (but they probably doesn’t explain anything, and besides, the blue Plane in the clip is not rotated by the Quat, but for debug-purposes it was created “directly as is” with code, in order to rule ot the Quats as the cause, see code far below) :

The blue rotated Plane was created from “raw” component inport values like so, so nothing strange is expected to have happened to the Plane itself.:

``````    var new_normal = focusPt - start_plane.Origin;
var new_plane = new Plane(start_plane.Origin, new_normal);
``````

Rotating this Plane using the Quaternion I produced from the two Planes gives the exact same result.

Now what? This isn’t very funny anymore.

// Rolf

Planes defined solely by Origin and Normal cannot mathematically be continuous. At some point a minor change in normal direction must yield a large change in plane axis direction. The algorithm which creates planes from normals doesn’t even attempt to minimise this since it cannot eliminate the problem anyway. The plane constructor which only takes an origin and a normal simply assumes you do not care about the orientation of the plane x and y axes.

If you have a starting plane and a target normal direction, you can transform the plane using Transform.Rotation(Vector3d, Vector3d, Point3d)

Of course if your target vector is anti-parallel to your initial vector, the orientation of the final plane will still be unpredictable.

Perhaps the Plane problem should be fixed by using Quaternions under the hood. One good reason for that - if I understood it correctly - is that an Indentity Quaternion with its four scalar values can be thought of as a “vector” plus a scalar for the rotation angle (which is reset to “no rotation”, which still is a defined rotation on the unit sphere) would take care of the ill-defined Planes. The missing rotation of a naked vector in space that is.

I noticed that Unity and ogre3D and other engines use Quaternions under the hood, and Eulers only in the UI, since Euler rotations is considered more intuitive by most developers.

In any case, the Plane problem is a PITA, especially GH is dragged down in the dirt becaiuse of it. Quaternions perhaps is the pill that cures the ill.

// Rolf

There’s always going to be at least one discontinuity left due to the hairy-ball theorem. You can’t comb them all away.

The number of discontinuities can be reduced by switching to a more expensive algorithm which uses minimum rotation instead of just cooking up ‘random’ perpendicular vectors, but you will still get directions in which the plane is very unstable (small perturbations of target vector yielding large perturbations in plane orientation) and one special direction that is fully unstable.

If your motions happen incrementally in time (such as is the case with for most transformations in games), then you can ‘reset’ the instability at each junction, pushing the unstable rotational direction as far away from the current orientation as possible, but if you start making large adjustments you will run into this one way or another.

The north pole and southpole on the sphere doesn’t have to be a big problem if only handling them consistently. Whether a rotation is “well defined” or not doesn’t have to be such a big problem of only handling it consistently.

I’d like to compare this consistency thing with how we go about in our daily lifes knowing little or nothing about so many things, without having a clue. We don’t even know what gravity actually is. There are astrophysicists pondering upon whether gravity is a attraction force or a repulsive force…

But as long as nature remains consistent we’re still doing “not too bad”.

// Rolf

Well, it currently is being handled consistently, just not in a consistent way you like. I don’t know what “well defined” means in this case.

Of course I would prefer “useful consistency” before any other arbitrary not-useful-or-intuitive-for-the-prime-use-case. Like gravity.

As a matter of fact, quaternions are oriented in the same way. As long as you keep it normalized you’re always oriented on the sphere. And you’re not rotated around the gravity vector.

That’s useful consistency, even if you don’t know where on earth you are.

// Rolf

So here’s an alternative way to construct a plane based on normal direction: NormalMinimalRotation.gh (3.6 KB)

It’s more continuous than the method used currently, but it does still suffer from unstable regions. You can explore them by dragging the point around.

Are there any more unstable regions than close to the origin? I couldn’t see any, or i passed them by too fast?

// Rolf

In my opinion there are not enough data here to let GH understand exactly which plane you are talking about …
Usually, in this case, I would chose a ‘UP’ direction (say a ‘Y’ direction or whatever …), so that he plane be well defined.
This way you can handle the special-case-points as you like/need.

Here’s the instabilities mapped onto a sphere: NormalMinimalRotation.gh (14.8 KB)

You can comb the two poles together into a di-pole, so there’s only one point that is utterly unstable. So between any two normal vectors on either side of the pole, the resulting planes will be opposed, and near the di-pole there’s a region where the plane orientation changes far more rapidly than the normal.

Yup, the Adjust Plane component does that. It creates a plane from normal, while inheriting as best as it can from the orientation of another plane.

1 Like

Since I’m working with Quaternions (which is all unit sphere) it makes sense to differ between “Northern hemisphere” and the Southern ditto. If need be also which quadrant.

I made a stable spherical orientation for my ellipsoid orientations using this technique, so I guess I will have to resort to that. But in complex systems it slows things down to do many checks.

// Rolf

1 Like

What is the strategy for the ajustment in that component? (would you share?)

I need to do this particular thing in code, so the component won’t help me this time.

I already know I can do this myself, but I also know that my method was costly (checking both angles for Spherical coordinates, phi and theta). Lots of trigonometry before arriving at the angles to check, and… not for free.

// Rolf

I think it does exactly what my C# component does as well, except my script always starts with WorldXY. Set up a minimal rotation between the old and new normal vectors, then transform the plane.

In my case this is would be - although perhaps most efficient - a bit silly.

This is because I’m doing quaternions in order to get stable rotations, aming at eventually producing transforms to be applied to other objects. But if I need to do the transform --> to get the quaternion --> to get the transform… I may start feeling a bit silly.

// Rolf

Are Quaternions a means or an end?

Both. In my case actually both. Project directives.

BTW, your transform example would be handled by quaternions very elegantly with one of the suggested methods, this one

• Quaternion.FromToRotation(Vector3d fromDirection, Vector3d toDirection);

With the quat one could then perform further artithmetics, interpolate linearly (Lerp) or spherically (Slerp) and many other things, like dual-quaternions with screw translations and… or directly convert to a transform.

Full freedom. So whether it is a means or an end is “not well defined” at this moment in time. Except for the clear directive to just use them.

// Rolf

Sounds like you’ll have to write some custom Quaternion maths then, the `Transform.Rotation` trick is the only way I know how to solve this within the current state of our SDK.

Yup. I started this, but I’m not very happy about the prospect of passing on RILQuaternions as a std transform type from GH component to GH component. I would have prefered using a standard library Rhino Quaternion. Oh well.

BTW, don’t forget to add Quaternion as a type in the Type Hint dialog. Quaternions are here to stay. Current zombie Rhino Planes is one important reason out of many good reasons…

Quaternions are used in medicine, molecular biology, quantum physics asf (for example, the half angle concept in quats play well with the halv-spin of elementary particles. A complete rotation thus is actually 720 degrees, not 360 < scratching head > ).

// Rolf

3 Likes