2D Rotational constraint impulse

Started by
7 comments, last by celloe 12 years, 4 months ago
Hi guys, I've been having some trouble implementing rotational min/max angle constraints. It's pretty straightforward with verlet integration but right now I'm using semi-implicit euler (subject to change) and velocity needs to be explicitly modified. I don't really know how to apply a rotational impulse..
With 3 points, p1, p2 and p3, all holding their own velocities and forces, I need to resolve the constraint of the angle between p1, p2 and p3 (p2 being the midpoint) such that min <= angle <= max. I assume what I should be doing is rotating p3 around p2 based on the difference between the desired and current angle, but that could get unstable and I don't really know where to start.

So far it's just basic angle detection from -PI to PI so it looks like this:
public function solveAngular() {
var ex = p2.x-p1.x;
var ey = p2.y-p1.y;
var fx = p3.x-p2.x;
var fy = p3.y-p2.y;
var dot = ex*fx+ey*fy;
var cross = ex*fy-ey*fx;
var angle = Math.atan2(cross, dot);

if (angle > min && angle < max) return;

var correction = 0.;
if (angle < min) correction = min-angle;
if (angle > max) correction = max-angle;

// Resolve
}


Obviously a little unoptimized at the moment, just trying to keep things relatively simple. Any help or insight is appreciated!
Advertisement
Hi Celloe,

I have made a damped angular spring code sample, which keeps any number of particles at any given angle relative to each other. Would you like to have a look at it?

Cheers,
Mike
That'd be great, yes please! (is it the shape matching one? I remember stalking that thread for days a while ago)
No, this is much simpler. It's basically just an angular version of Hookes law of elasticity. The tricky part is calculating angular properties for each pair of particles. I'll upload a commented version tomorrow (european time).
Brilliant, thanks. I'm in Europe too, looking forward to it!
Hi again,

As promised, here's a zipped folder containing commented code sample, vector library and exe file. The program is written i freebasic, which is a very fast, object oriented basic dialect. If you're having trouble figuring out how it works I don't mind explaining it in more detail.

Cheers,
Mike
Thank you! That's genius.. I'd had the same sort of idea as the method you're using, just wasn't sure how to implement it. The code's a little difficult for me to decipher (not used to freebasic syntax) but I'm sure if I spend a bit of time on it I'll be able to crack it. 2 initial questions though:
In the "get angular spring angle" section, how did you derive the method to get the angle of the joint? And I assume dotnormal is just the normalised dot product, or is it literally "normal" to the dot product in the sense that it's geometrically perpendicular?

Another thing.. you mention the spring torque based on sine angle being less efficient but faster - what do you mean less efficient? It seems like it'd be overall better as an optimization to avoid having to calculate the atan2 which'd require the cosine and sine.

Thank you! That's genius.. I'd had the same sort of idea as the method you're using, just wasn't sure how to implement it. The code's a little difficult for me to decipher (not used to freebasic syntax) but I'm sure if I spend a bit of time on it I'll be able to crack it. 2 initial questions though:
In the "get angular spring angle" section, how did you derive the method to get the angle of the joint? And I assume dotnormal is just the normalised dot product, or is it literally "normal" to the dot product in the sense that it's geometrically perpendicular?

Another thing.. you mention the spring torque based on sine angle being less efficient but faster - what do you mean less efficient? It seems like it'd be overall better as an optimization to avoid having to calculate the atan2 which'd require the cosine and sine.


I derive the angles between particles just like in your example, except that I store them both as scalar and a vector, where the x and y components represent cosine and sine angle. This is the same as a normalized distance vector. The dotnormal is exactly what you assume, the perpendicular dot product, or "2d cross product". Since a true cross product always returns a vector for any number of dimensions, and dot returns a scalar, I chose to call it that.

The sine based spring behaves slightly different from the "full" atan2 based one. Torque is largest at 90 degrees and goes towards zero as the distortion angle goes towards 180 degrees. This is due to the simple fact, that the value of sine is one for 90 degrees and zero for 0 and 180 degrees. The atan2 based spring works more like a Hooke's law spring in the way that it exerts a larger torque the more it is distorted. If you do not clamp angles to the (-pi, pi) range, you can even wind up the spring several full 360 degree turns.

And to save you a little trouble decipering my 600 lines of obfuscated, half finished code - this is how the spring works:

A simple "linear" Hookes law damped spring looks like this:

Force = -Stiffness coefficient * (length - rest length) - Damping coefficient * velocity projected onto normalized distance vector.

The corresponding angular spring looks like this:

Torque = -Stiffness coefficient * (angle - rest angle) - Damping coefficient * difference in angular velocity

Applying this between two rigid bodies is very simple, since angle and angular velocity data are already explicitly there. Applying it to sets of particles is slightly more difficult, because you have to calculate angle and angular velocity for each particle pair "as if" they were rigid bodies. We've already discussed anlge, but what about angular velocity:

Angular velocity = Angular momentum / moment of inertia

The moment of inertia for a particle pair is the sum of r^2 * mass, where r is the distance between the center of mass and the particle. The angular momentum is the sum of r cross momentum, which in this case is r dotnormal mass * velocity.

Hope this helps!

Cheers,
Mike
That made things way clearer, thank you! Managed to get it up and running. I'd never thought of that way of converting torque to particle acceleration! Only thing I'm going to change now is to work on angles originating from a 0,0 position as opposed to.. "relative angles" between joints, if you know what I mean. For instance, if I make a square out of 4 joints, I have to set each joint min/max angle to 90 degrees, as opposed to however many degrees it'd logically be from the origin. Shouldn't be too difficult!

Thanks again. I wonder if I can somehow make it behave in a "continuous collision" sense, so that fast rotations don't distort the structures too much. Could be interesting to try.

This topic is closed to new replies.

Advertisement