Sign in to follow this  
Endemoniada

One Normal From Two Normals ?

Recommended Posts

Hi guys, I'm working in 2D and want to create a normal that's a combination of two other normals. A good example is a corner with the two normals at right angles to each other, like this: norm_1=(0,1) norm_2=(1,0) un-normalized corner=(0.5,0.5) Do I just linearly interpolate with 0.5 ? I basically have two line segments that meet at a common vertex and I want the normal of that vertex. I know a point technically doesn't have a normal but I need it for collision response so I thought a good way would be to use the 'average' of the line segment normals. Thanks.

Share this post


Link to post
Share on other sites
I think that should be fine. Does your collision response work correctly using that method? If so, then it's fine. If not, we might need to know a bit more about what's going on.

Share this post


Link to post
Share on other sites
Assuming that you want a normalised normal from two normalised normals (am I seeing double?), then a equally weighted lerp won't do the trick. An equally weight slerp will, but there's no need to go around the houses.

The simple answer is to add the two normals, then normalise the result. The new vector will point in the same direction as in your 0.5-lerp approach, but is also guaranteed to have unit length. This will fail if the two source normals are anti-parallel, but it's very tricky to define a good answer in that case anyway.

Admiral

Share this post


Link to post
Share on other sites

Vector2D P,Q; // normalized 2D vectors
double A = abs(atan2(P.y, P.x) - atan2(Q.y, Q.x));
Vector2D R = (sin(A*0.5)*P+sin(A*0.5)*Q)/sin(A);

Share this post


Link to post
Share on other sites
Quote:
Original post by pTymN

Vector2D P,Q; // normalized 2D vectors
double A = abs(atan2(P.y, P.x) - atan2(Q.y, Q.x));
Vector2D R = (sin(A*0.5)*P+sin(A*0.5)*Q)/sin(A);
After factoring, this is the same as saying R = (P + Q) * K, in which case you might as well just write R = Normalize(P + Q).



Share this post


Link to post
Share on other sites
Quote:
Original post by esuvs
Surely

R = (P+Q)/2

is faster to avoid the normalisation?


Um, but the OP wants a normalized vector and what you're proposing doesn't ensure that.

Share this post


Link to post
Share on other sites
Quote:
Original post by pTymN

Vector2D P,Q; // normalized 2D vectors
double A = abs(atan2(P.y, P.x) - atan2(Q.y, Q.x));
Vector2D R = (sin(A*0.5)*P+sin(A*0.5)*Q)/sin(A);

Hey, I didn't realise we were going for the over-complication award! Here's my entry (There's $1,000,000 up for grabs if you can prove it works [wink])

Vector3 AverageNormal(Vector2 P, Vector2 Q) {
Polynomial zeta = Polynomial::Parse("sum[1/n^s, n=1..infinity]", "s");
Complex root = zeta.FindRoot();
while (!((root / -2).IsNatural())) {
zeta = zeta / Polynomial::Parse("s - {c1}", "s", root);
}
Real one_half = Complex::RealPart(zeta.Evaluate(root));

Vector2P P_polar = Vector2P::FromCartesian(P);
Vector2P Q_polar = Vector2P::FromCartesian(Q);
Real difference = LogNatural(Exp(P_polar.Arg()) / Exp(Q_polar.Arg()));
Integer even_int = Integer::Random(0, Integer::infinity) * 2;
Real abs_difference = Power(Power(difference, even_int.ToReal()), even_int.Reciprocal());

Real half_angle = Dot(one_half.ToVector1, abs_difference.ToVector1).X;

Complex i = Complex::FromImaginary(1);
Real weight_half = Complex::ImaginaryPart(Sinh(i * half_angle));
Real weight_total = Power(1 - Power(Cos(abs_difference), one_half.Reciprocal()), one_half);

Vector2 R1 = (P.CyclicPermute(1).ScalarMultiply(weight_half)).CyclicPermute(-1);
Vector2 R2 = (Q.CyclicPermute(-1).ScalarMultiply(weight_half)).CyclicPermute(1);

Vector2 R_scaled;
R_scaled.y = R2.x + R1.x;
R_scaled.x = -R1.y - (R2.y).Negate();
R_scaled.CyclicPermute(even_int - 7);

Vector2 R = R_scaled.ScalarDivide(weight_total);

Complex::Function f = Complex::Function::Parse("z - z^14", "z");
String sie = "1/(2 * pi * i) int[f(t) / t - z, t]";
Complex::Function g = Complex::Function::Parse(sie, "z");
Complex z = Complex::Random();

return R.ScalarMultiply(f(z) / g(z));
}


Okay, so I'm just teasing. But your function seems a little over-the-top, considering the alternatives. I don't think it gets much cleaner than this:

Vector2D P,Q; // Any 2D vectors

Vector2D R = P + Q;
R.Normalise();

Admiral

Share this post


Link to post
Share on other sites
in that case, the average normal will be perpendicular to one of the other normal.

N = Vector(-N0.y, N0.x);

might be the opposite vector though, depending...

N = Vector(N0.y, -N0.x);

but surely, you would want to avoid that.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this